紧急需求‼️实现iOS启动图动态置灰
前言
相信这几天各大互联网应用首页置灰已经接踵而至,事情缘由我就不太赘述。毫无疑问,我司从30号当晚就收到紧急需求,我们要求1号必须紧急发版,除了常规的首页支持配置的动态置灰外,我们还要求另外一个需求就是,启动图也需要支持动态配置灰功能,经过几个同事的努力,于1号当晚顺利的发版了,第二天一早便成功上线,在此记录一下实现iOS启动图动态置灰的方案心得。
方案过程
实话说,当我接到此需求时,我负责的是实现iOS启动图动态置灰,当时我不太确认是否能实现,我能想到的是马上搜百度、谷歌、掘金等看是否有现成的轮子,答案肯定是有的,分别是
此方案非常轻量级,只有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;
}
稍微吐槽下这个库,此库也是我一开始使用的。它也是基于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。
链接:https://juejin.cn/post/7172983260966813709
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。