1,看需求:在节日活动期间通常会看到某些大厂的AppIcon主动就变化了,咱们也需要在节日期间让用户不更新新版别的情况下,切换咱们的AppIcon。
2,列计划:1,热更新 2,发版别并且强制更新 3,AppIcon主动切换。
3,选计划:3
4,具体实现:
1,配图:把图片拖进工程资源文件夹,并取个高雅且适宜的姓名,如下图:
2,装备Info.plist文件,增加Icon files (iOS 5), 它是个字典,其中默认有两个Key值,分别是:
**Primary Icon(主icon):**设置app的主icon,能够在这里的Icon files数组内增加,有多个的话,顺次增加,也能够这里不必填写,直接在Assets.xcassets 里装备;
**Newsstand Icon(期刊icon):**设置所有用户订阅的报刊和杂志类的图标,目前咱们用不到,先不必管。
要点:在Icon files (iOS 5),内增加一个Key:CFBundleAlternateIcons ,类型为Dictionary。****在这个字典里装备咱们所有需要动态修改的AppIcon:键为AppIcon的称号,值为一个字典(这个字典里包括两个键:CFBundleIconFiles,其值类型为Array,内容为icon的称号。如下图:
3,代码编写:我用的****Swift,这个代码MSObjectTools.exchangeAlternateIcon(withName: iconName)
是用来替换原有的办法,便是注释掉的那部分。假如不替换的话,每次切换Icon成功之后,会有一个弹窗提示很烦。暂时没找到Swift替换IMP的办法。所以引入了一个OC的类。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
///注册后端云
self.registerLearnCloud()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self .changeAppIcon(with: "appIcon_earth")
}
return true
}
替换图标办法
///替换图标办法
func changeAppIcon(with name: String?) {
guard UIApplication.shared.supportsAlternateIcons else {
return
}
guard let iconName = name, iconName.count > 0 else {
return
}
MSObjectTools.exchangeAlternateIcon(withName: iconName)
// UIApplication.shared.setAlternateIconName(iconName) { error in
// print("切换图标犯错,原因:\(error.debugDescription)")
// }
}
替换IMP办法
#import <UIKit/UIKit.h>
#import "MSObjectTools.h"
@implementation MSObjectTools
///履行换图标的办法
+ (void)exchangeAlternateIconWithName:(NSString *)iconName {
if ([[UIApplication sharedApplication] respondsToSelector:@selector(supportsAlternateIcons)] &&
[[UIApplication sharedApplication] supportsAlternateIcons])
{
NSMutableString *selectorString = [[NSMutableString alloc] initWithCapacity:40];
[selectorString appendString:@"_setAlternate"];
[selectorString appendString:@"IconName:"];
[selectorString appendString:@"completionHandler:"];
SEL selector = NSSelectorFromString(selectorString);
IMP imp = [[UIApplication sharedApplication] methodForSelector:selector];
void (*func)(id, SEL, id, id) = (void *)imp;
if (func)
{
func([UIApplication sharedApplication], selector, iconName, ^(NSError * _Nullable error) {});
}
}
}
@end
4,注意事项:
-
1,不能在didFinishLaunchingWithOptions调用这个办法,假如必须在didFinishLaunchingWithOptions里调用的话,必须加延时,否则会报被撤销Error
-
2,setAlternateIconName 这个办法在10.3以后才有,注意体系版别。
-
3,icon资源文件需要在项目目录下,不能是Assets.xcassets中的图片,否则无效。
后续优化:
我在调用func changeAppIcon(with name: String?)
这个办法之后,活动结束,发现无法复原。所以做出了如下优化,把完结结果通过block回调出来:
///履行换图标的办法
+ (void)exchangeAlternateIconWithName:(NSString *)iconName completeBlock:(void (^)(NSError * _Nullable error))completed {
if ([[UIApplication sharedApplication] respondsToSelector:@selector(supportsAlternateIcons)] &&
[[UIApplication sharedApplication] supportsAlternateIcons])
{
NSMutableString *selectorString = [[NSMutableString alloc] initWithCapacity:40];
[selectorString appendString:@"_setAlternate"];
[selectorString appendString:@"IconName:"];
[selectorString appendString:@"completionHandler:"];
SEL selector = NSSelectorFromString(selectorString);
IMP imp = [[UIApplication sharedApplication] methodForSelector:selector];
void (*func)(id, SEL, id, id) = (void *)imp;
if (func)
{
func([UIApplication sharedApplication], selector, iconName, ^(NSError * _Nullable error) {
completed(error);
});
}
}
}
调用的时分
///替换体系图标
func changeAppIcon(with name: String?) {
if name == UserDefaults.MSOtherRecordInfo.string(forKey: .autoAppIcon) {
return
}
if #available(iOS 10.3, *) {
guard UIApplication.shared.supportsAlternateIcons else {
return
}
guard let iconName = name, iconName.count > 0 else {
return
}
MSObjectTools.exchangeAlternateIcon(withName: iconName) { error in
if error == nil {
UserDefaults.MSOtherRecordInfo.set(stringValue: iconName, forKey: .autoAppIcon)
}
}
}
}
先在UserDefault里记录下替换AppIcon的图片称号,假如称号相同的话,就不再进行替换了。
假如活动结束,想换回之前的,需要一张和AppIcon同样的图片。比如我的appIcon_earth是活动期间的用的,appIcon_default是和App主图标一样的图片。假如活动结束,后台接口把图片姓名装备成appicon_default,就OK了。