本文正在参与「金石计划 . 分割6万现金大奖」
前语
相信这几天各大互联网应用主页置灰现已接踵而至,工作缘由我就不太赘述。毫无疑问,我司从30号当晚就收到紧迫需求,咱们要求1号有必要紧迫发版,除了常规的主页支撑装备的动态置灰外,咱们还要求另外一个需求便是,发动图也需求支撑动态装备灰功用,经过几个同事的努力,于1号当晚顺畅的发版了,第二天一早便成功上线,在此记录一下完成iOS发动图动态置灰的计划心得。
计划进程
实话说,当我接到此需求时,我负责的是完成iOS发动图动态置灰,其时我不太确认是否能完成,我能想到的是立刻搜百度、谷歌、等看是否有现成的轮子,答案肯定是有的,分别是
- BBADynamicLaunchImage
此计划十分轻量级,只要BBADynamicLaunchImage一个类,功用也只要一个,即查找系统缓存的发动图路径,运用咱们提供的UIImage替换掉。其他版别操控本非必要需求咱们自己代码操控即可。终究我也是直接采用了这个计划,其他操控由我代码自己编写核心办法如下。PS:(虽然提供iOS13之前的发动图路径查找,可是经过我实测一台iOS12的设备是不收效的,只要iOS13意思机型收效)
/// 系统发动图缓存路径
+ (NSString *)launchImageCacheDirectory {
NSString *bundleID = [NSBundle mainBundle].infoDictionary[@"CFBundleIdentifier"];
NSFileManager *fm = [NSFileManager defaultManager];
// iOS13之前
NSString *cachesDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSString *snapshotsPath = [[cachesDirectory stringByAppendingPathComponent:@"Snapshots"] stringByAppendingPathComponent:bundleID];
if ([fm fileExistsAtPath:snapshotsPath]) {
return snapshotsPath;
}
// iOS13
NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
snapshotsPath = [NSString stringWithFormat:@"%@/SplashBoard/Snapshots/%@ - {DEFAULT GROUP}", libraryDirectory, bundleID];
if ([fm fileExistsAtPath:snapshotsPath]) {
return snapshotsPath;
}
return nil;
}
- LLDynamicLaunchScreen
稍微吐槽下这个库,此库也是我一开始运用的。它也是根据BBADynamicLaunchImage做了一些拓展。比如版别操控,可是它内置的版别操控有漏洞,它只支撑CFBundleShortVersionString,也便是咱们俗称的大版别,假如我build号改了版别号不变岂不是有问题?(这也是我打包后不收效调试了好久才发现的问题)而且要支撑动态置灰,不发版康复原图就更加有问题。最后也是弃用了,当然这个库支撑暗黑形式下的发动图,可是我自身app便是不支撑的这个功用就聊胜于无了,终究该用了上边的计划,动态操控由我自己处理。
发动图怎么置灰
要完成发动图和原图一模一样只是变成灰白,这里就稍微要花一点点心思了。众所周知咱们现在iOS发动图都是直接用LaunchScreen这个Storyborad生成的,那咱们是否能加载这个LaunchScreen,然后截取UIView的图片,之后再经过bitmap转换成一张灰白图?答案是清楚明了的,代码如下。
首要咱们要给LaunchScreen定义一个id,因为默许没有人去加载它,它也没有id。
代码如下:
生成发动图原图或灰白图办法,注意此办法要在主线程跑。
+ (UIImage *)createLaunchScreenImage:(BOOL)isNeedGray {
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"LaunchScreen"];
[vc loadViewIfNeeded];
vc.view.frame = UIScreen.mainScreen.bounds;
UIImage *image = [vc.view snapshotImage];
if (isNeedGray) {
image = [image createGrayImage];
}
return image;
}
UIView截图
func snapshotImage() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0);
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
生成灰白图办法,因为发动图有必要size匹配,所以scale那些要处理好。
-(UIImage*)createGrayImage {
int width = self.size.width * self.scale;
int height = self.size.height * self.scale;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context =CGBitmapContextCreate(nil,
width,
height,
8,// bits per component
0,
colorSpace,
kCGBitmapByteOrderDefault);
CGColorSpaceRelease(colorSpace);
if(context ==NULL) {
return nil;
}
CGContextDrawImage(context,
CGRectMake(0,0, width, height), self.CGImage);
UIImage*grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context) scale:self.scale orientation:self.imageOrientation];
CGContextRelease(context);
return grayImage;
}
动态替换
咱们只需求请求后台装备,需求灰白就提供灰白图,当装备失效,需求复原时候,依据上面办法,直接烘托一个LaunchScreen原图即可,当然其中还要做好耐久化操控,不要处理屡次替换,替换收效后不再处理。
结尾
以上便是我完成此次iOS发动图动态置灰的全进程,因为进程的艰苦,加之我自己是一个Swifter。估计不久将来,我也会根据Swift写一个稍微友好点的库,在此立个Flag。