博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[iOS]动态修改app 图标(icon)
阅读量:3753 次
发布时间:2019-05-22

本文共 6273 字,大约阅读时间需要 20 分钟。

动态修改app的图标,就是在不重新安装app的情况下,可以修改当前的icon图标;在某些情况下,是有这个需求的;例如,可以更换主题的app中,一般都会有一套完整的主题包含相应的icon;还有就是一些节日主题的icon或者促销的icon,例如淘宝、京东等的节日icon。

在iOS 10.3之后,苹果官方提供了相关的API来实现这个功能,主要是下面这几个方法:

@interface UIApplication (UIAlternateApplicationIcons)// 如果为NO,表示当前进程不支持替换图标@property (readonly, nonatomic) BOOL supportsAlternateIcons NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));// 传入nil代表使用主图标. 完成后的操作将会在任意的后台队列中异步执行; 如果需要更改UI,请确保在主队列中执行.- (void)setAlternateIconName:(nullable NSString *)alternateIconName completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));// 如果alternateIconName为nil,则代表当前使用的是主图标.@property (nullable, readonly, nonatomic) NSString *alternateIconName NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));@end

方法很简单,但是使用之前需要进行一些配置:

1. 配置icon

添加图片icon

动态修改的icon不能放在 Assets.xcassets 里,但是正常的主icon还是可以在这里设置的,也可以按下面的方法来设置;

首先,把需要修改的icon放在一个文件夹内:

 

icons

其文件夹内是这样的

 

这里每种icon我只放了一个,如果有多个尺寸的icon,也可以直接全放进去:

多尺寸icon

 

然后,文件夹会变成这样:

这里的icon名称只需要和下面配置一致即可

配置info.plist

在info.plist中右键 -> Add Row :

输入Icon... 会有提示,选择Icon files(iOS 5)

 

这时候,内容是这样的:

 

这里的Icon files(iOS 5)是个字典,其中可包含的Key值有CFBundlePrimaryIcon -> Primary Icon

CFBundleAlternateIcons
UINewsstandIcon -> Newsstand Icon

这里的Primary Icon是设置app的主icon,可以在这里的Icon files数组内添加,有多个的话,依次添加,也可以这里不用填写,直接在Assets.xcassets 里配置;

下面的Newsstand Icon,暂时用不到,不用管,也可以删除。

在 Icon files(iOS 5)内添加一个Key: CFBundleAlternateIcons ,类型为字典,在这个字典里配置我们所有需要动态修改的icon:键为icon的名称,值为一个字典(这个字典里包含两个键:CFBundleIconFiles,其值类型为Array,内容为icon的名称;UIPrerenderedIcon,其值类型为bool,内容为NO,也可以不加此key),例如:

把第一步中添加的图片全部添加进来就是这样的:

 

到此,info.plist的配置即完成了;

或者将info.plist文件以 Source code 方式打开,添加以下代码:

CFBundleIcons
CFBundleAlternateIcons
rain
CFBundleIconFiles
rain
UIPrerenderedIcon
snow
CFBundleIconFiles
snow
UIPrerenderedIcon
sunshine
CFBundleIconFiles
sunshine
UIPrerenderedIcon
cloudy
CFBundleIconFiles
cloudy
UIPrerenderedIcon
CFBundlePrimaryIcon
CFBundleIconFiles
UIPrerenderedIcon
UINewsstandIcon
CFBundleIconFiles
UINewsstandBindingType
UINewsstandBindingTypeMagazine
UINewsstandBindingEdge
UINewsstandBindingEdgeLeft

如果是添加了多个尺寸icon,也要在这里分别配置,以上面添加的sunshine图标为例:

使用的时候还是使用sunshine进行赋值即可!

代码

配置完成后,代码部分就比较简单了:

- (void)changeAppIconWithName:(NSString *)iconName {    if (![[UIApplication sharedApplication] supportsAlternateIcons]) {        return;    }        if ([iconName isEqualToString:@""]) {        iconName = nil;    }    [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {        if (error) {            NSLog(@"更换app图标发生错误了 : %@",error);        }    }];}

在需要修改icon的地方调用这个方法,并把相应的icon名称传进去即可:

- (IBAction)snow:(id)sender {    [self changeAppIconWithName:@"snow"];}- (IBAction)rain:(id)sender {    [self changeAppIconWithName:@"rain"];}- (IBAction)cloudy:(id)sender {    [self changeAppIconWithName:@"rain"];}- (IBAction)sunshine:(id)sender {    [self changeAppIconWithName:@"sunshine"];}

示意图:

 

示意图

设置iPad动态图标

iPad的动态图标设置和上面步骤基本一样,有的文章说是将 CFBundleIcons 改为 CFBundleIcons~ipad,即:

iPad

但是,在测试中发现,使用上面的key值也是可以实现动态改变的,即不做任何修改,iPhone和iPad使用相同的配置,即:CFBundleIcons。

去掉更换icon时的弹框

从上面的示意图可以发现,在设置icon的时候,会有个系统弹框,这样有时候会不太友好,我们可以使用Runtime,对UIViewController进行扩展来隐藏这个弹框:

// UIViewController+LQNoPresent.h#import 
@interface UIViewController (LQNoPresent)@end// UIViewController+LQNoPresent.m#import "UIViewController+LQNoPresent.h"#import
@implementation UIViewController (LQNoPresent)+ (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(lq_presentViewController:animated:completion:)); method_exchangeImplementations(presentM, presentSwizzlingM); });}- (void)lq_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion { if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {// NSLog(@"title : %@",((UIAlertController *)viewControllerToPresent).title);// NSLog(@"message : %@",((UIAlertController *)viewControllerToPresent).message); UIAlertController *alertController = (UIAlertController *)viewControllerToPresent; if (alertController.title == nil && alertController.message == nil) { return; } } [self lq_presentViewController:viewControllerToPresent animated:flag completion:completion];}@end

这样在切换图标的时候就没有系统的弹框了:

去掉系统弹框

参考文章

作者:流火绯瞳
链接:https://www.jianshu.com/p/69313970d0e7
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的文章
HTTP over SSL/TLS
查看>>
CentOS安装fortune+cowsay
查看>>
用vue创建一个项目
查看>>
$listeners与.native的使用
查看>>
熟悉Linux 下静态库.a 与.so 库文件的生成与使用——实例
查看>>
算法训练 1的个数(输入正整数n,判断从1到n之中,数字1一共要出现几次。例如1123这个数,则出现了两次1。例如15,那么从1到15之中,一共出现了8个1。)
查看>>
算法训练 素因子去重(给定一个正整数n,求一个正整数p,满足p仅包含n的所有素因子,且每个素因子的次数不大于1)
查看>>
算法训练 二进制数数( 给定L,R。统计[L,R]区间内的所有数在二进制下包含的“1”的个数之和。   如5的二进制为101,包含2个“1”。)
查看>>
第十届MathorCup高校数学建模D题解题思路
查看>>
2020年高教社杯全国大学生数学建模竞赛赛题 C题分析与思路!(持续更新)
查看>>
2020年高教社杯全国大学生数学建模竞赛赛题 B题分析与思路!(持续更新)
查看>>
蓝桥杯真题 18省4-测试次数 x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。 各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐
查看>>
蓝桥杯真题 19省3-数列求值 给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求第 20190324 项的最后 4 位数字。
查看>>
大小写字母转换函数tolower();的用法
查看>>
蓝桥杯 15校4-7对数字 今有7对数字:两个1,两个2,两个3,...两个7,把它们排成一行。 要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字。如下就是
查看>>
蓝桥杯真题 17省10-k倍区间 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i
查看>>
TCP协议的流量控制
查看>>
TCP连接的三次握手过程,为什么不是两次或四次?
查看>>
小白都能看懂的DNS解析过程
查看>>
HTTP和HTTPS的区别?描述HTTPS的工作过程
查看>>