動(dòng)態(tài)修改app的圖標(biāo),就是在不重新安裝app的情況下,可以修改當(dāng)前的icon圖標(biāo);在某些情況下,是有這個(gè)需求的;例如,可以更換主題的app中,一般都會(huì)有一套完整的主題包含相應(yīng)的icon;還有就是一些節(jié)日主題的icon或者促銷的icon,例如淘寶、京東等的節(jié)日icon。
在iOS 10.3之后,蘋果官方提供了相關(guān)的API來(lái)實(shí)現(xiàn)這個(gè)功能,主要是下面這幾個(gè)方法:
@interface UIApplication (UIAlternateApplicationIcons)
// 如果為NO,表示當(dāng)前進(jìn)程不支持替換圖標(biāo)
@property (readonly, nonatomic) BOOL supportsAlternateIcons NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));
// 傳入nil代表使用主圖標(biāo). 完成后的操作將會(huì)在任意的后臺(tái)隊(duì)列中異步執(zhí)行; 如果需要更改UI,請(qǐng)確保在主隊(duì)列中執(zhí)行.
- (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,則代表當(dāng)前使用的是主圖標(biāo).
@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
動(dòng)態(tài)修改的icon不能放在 Assets.xcassets 里,但是正常的主icon還是可以在這里設(shè)置的,也可以按下面的方法來(lái)設(shè)置;
首先,把需要修改的icon放在一個(gè)文件夾內(nèi):

1.配置info.plist
在info.plist中右鍵 -> Add Row :
輸入Icon... 會(huì)有提示,選擇Icon files(iOS 5)

這時(shí)候是這樣的

這里的Icon files(iOS 5)是個(gè)字典,其中可包含的Key值有
這里的Primary Icon是設(shè)置app的主icon,可以在這里的Icon files數(shù)組內(nèi)添加,有多個(gè)的話,依次添加,也可以這里不用填寫,直接在Assets.xcassets 里配置;
下面的Newsstand Icon,暫時(shí)用不到,不用管,也可以刪除。
在 Icon files(iOS 5)內(nèi)添加一個(gè)Key: CFBundleAlternateIcons ,類型為字典,在這個(gè)字典里配置我們所有需要?jiǎng)討B(tài)修改的icon:鍵為icon的名稱,值為一個(gè)字典(這個(gè)字典里包含兩個(gè)鍵:CFBundleIconFiles,其值類型為Array,內(nèi)容為icon的名稱;UIPrerenderedIcon,其值類型為bool,內(nèi)容為NO,也可以不加此key),例如

把第一步中添加的圖片全部添加進(jìn)來(lái)就是這樣的:

到此,info.plist的配置即完成了;
注意 :切記名字一定要統(tǒng)一activityIcon圖片名稱和info.plist文件配置
代碼來(lái)了
- (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圖標(biāo)發(fā)生錯(cuò)誤了 : %@",error);
}
}];
}
去掉更換icon時(shí)的彈窗
從上面的示意圖可以發(fā)現(xiàn),在設(shè)置icon的時(shí)候,會(huì)有個(gè)系統(tǒng)彈框,這樣有時(shí)候會(huì)不太友好,我們可以使用Runtime,對(duì)UIViewController進(jìn)行擴(kuò)展來(lái)隱藏這個(gè)彈框:
UIViewController+LQNoPresent.h
#import <UIKit/UIKit.h>
@interface UIViewController (LQNoPresent)
@end
UIViewController+LQNoPresent.m
#import "UIViewController+LQNoPresent.h"
#import <objc/runtime.h>
@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