iOS-动态更换图标

「这是我参与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>
复制代码

完成之后大概就是这个样子

image.png

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
复制代码

通过上述代码就可以拦截到这个强制性的弹窗, 这样就解决了这个问题了

结语

相对来说逻辑简单, 代码易懂, 其实也就是一个拓展的方案, 可能有人对这方面涉猎不多, 可能项目中也不会用到, 就当一个备忘了, 如果有更好的想法, 请告诉我, 谢谢!

猜你喜欢

转载自juejin.im/post/7033422707626606605
今日推荐