動態更換app的圖標,就是在不重新安裝app的情況下,可以動態更黃當前的icon圖標。
該方法只能在系統版本iOS10.3及以上版本才可以使用。
具體如何操作,請看:
1、新建測試項目,設置項目的主app圖標。方式和正常設置AppIcon方式一樣。
1.1】在Assets.xcassets文件中設置AppIcon,如下圖:
1.2】在TARGETS—>General—>App Icons and Lauch Images—>App Icons Source設置圖標來源:AppIcon
效果圖如下:
2、配置需要動態展示的App圖標圖片
2.1】添加圖片
動態更換的icon不能放在Assets.xcassets里!但是正常的主icon還是可以在Assets.xcassets里設置的,也可以按下面的方法來設置(鑒于很多應用是在迭代更新版本中有了動態更換圖標的需求,主icon一般都是在Assets.xcassets里設置過了,所以我們的主icon也是放在Assets.xcassets里)。
新建一個文件夾AppIcons,將需要展示的圖片放在里面。如圖所示,我加了4種可以更換的圖標,每種圖標的大小不盡相同。
2.2】配置info.plist文件
路徑:TARGETS—>Info—>Custom iOSTarget Properties
在info.plist中右鍵 -> Add Row :
輸入Icon... 會有提示,選擇Icon files(iOS 5)
這里的Icon files(iOS 5)是個字典,其中默認包含兩個Key值,分別是:
Primary Icon(主icon):設置app的主icon,可以在這里的Icon files數組內添加,有多個的話,依次添加,也可以這里不用填寫,直接在Assets.xcassets 里配置;
Newsstand Icon(期刊icon):設置所有用戶訂閱的報刊和雜志類的圖標,目前我們用不到,先不用管。
在 Icon files(iOS 5)內添加一個Key: CFBundleAlternateIcons ,類型為字典。
在這個字典里配置我們所有需要動態修改的icon:鍵為icon的名稱,值為一個字典(這個字典里包含兩個鍵:CFBundleIconFiles,其值類型為Array,內容為icon的名稱;UIPrerenderedIcon,其值類型為bool,內容為NO,也可以不加此key)
配置完成!
3、更換AppIcon圖標
代碼如圖所示:- (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);
}
}];
}
效果圖如下:ps: 經測試,一個AppIcon圖標,并不需要上傳多張尺寸的圖片,傳一張圖,系統也可以根據圖片名展示出來。不過,如果圖片過小的話, 圖標會展示的比較模糊。
4、去掉更換icon時的彈框
在設置icon的時候,會有個系統彈框,這樣有時候會不太友好,我們可以使用Runtime,對UIViewController進行擴展來隱藏彈框。
// UIViewController+XZPresent_NoAlert.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIViewController (XZPresent_NoAlert)
@end
NS_ASSUME_NONNULL_END
// UIViewController+XZPresent_NoAlert.m
#import "UIViewController+XZPresent_NoAlert.h"
#import <objc/runtime.h>
@implementation UIViewController (XZPresent_NoAlert)
+ (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(xz_presentViewController:animated:completion:));
method_exchangeImplementations(presentM, presentSwizzlingM);
});
}
- (void)xz_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;
}
}
[self xz_presentViewController:viewControllerToPresent animated:flag completion:completion];
}
@end