「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」
前言
项目开发过程中,肯定会有更换项目图标的需求存在,好比我们做的电商项目, 每逢节日的时候就会给原先的图标上加一些特色的东西, 就比如淘宝的双11, 它的图标就有双11的标记, 像是这样的功能, 需要UI重新制作图标,然后程序员打包进APP,然后进行发版 审核 发布等等一系列流程, 还是比较麻烦的, 那么能不能将这一部分工作简化呢?
还是有的, 就好比我们今天要说的动态更换图标, 注意这里的动态不是指服务器下发图标来改变, 而是我们把图标提前打包入APP, 然后在指定的时间或者某一个操作之后就改变APP的图标.
下面就来说说具体的操作流程, 相对来说还是比较简单的.
实现
首先我们在项目中的info.plist中
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
</dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>g2</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>g2</string>
</array>
</dict>
<key>g3</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>g3</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
</dict>
复制代码
完成之后大概就是这个样子
CFBundlePrimaryIcon 对应的就是默认的图标 而g2 g3 就是我们的使用到的动态更换的图标
将动态更换的图标不能放置在asset中, 需要放到项目中以文件的形式保存.
下面就是如何在代码中动态更换图标
- (void)setIconname:(NSString *)name {
UIApplication *appli = [UIApplication sharedApplication];
//判断系统是否支持切换icon
if ([appli supportsAlternateIcons]) {
//切换icon
[appli setAlternateIconName:name completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"error==> %@",error.localizedDescription);
}else{
NSLog(@"done!!!");
}
}];
}
}
复制代码
name 就是动态更换图标的的名称, 也就是我们在info.plist文件中制定的名称
如果想切换到默认的图标如何操作呢? name设置为nil, 然后调用这个函数就可以实现了.
但是这里有个比较恶心的问题, 调用setAlternateIconName
的时候, 系统会自动强制弹窗提醒, 但是这样不利于用户的体验, 那么咱们就需要把这个弹窗给干掉.
这里就需要用到我们强大的runtime
#import <objc/runtime.h>
@implementation UIViewController (Ex)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method presentM = class_getInstanceMethod(self.class, @selector(presentViewController:animated:completion:));
Method presentSwizzlingM = class_getInstanceMethod(self.class, @selector(cg_presentViewController:animated:completion:));
method_exchangeImplementations(presentM, presentSwizzlingM);
});
}
- (void)cg_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {
UIAlertController *alertController = (UIAlertController *)viewControllerToPresent;
if (alertController.title == nil && alertController.message == nil) {
return;
} else {
[self cg_presentViewController:viewControllerToPresent animated:flag completion:completion];
return;
}
}
[self cg_presentViewController:viewControllerToPresent animated:flag completion:completion];
}
@end
复制代码
通过上述代码就可以拦截到这个强制性的弹窗, 这样就解决了这个问题了
结语
相对来说逻辑简单, 代码易懂, 其实也就是一个拓展的方案, 可能有人对这方面涉猎不多, 可能项目中也不会用到, 就当一个备忘了, 如果有更好的想法, 请告诉我, 谢谢!