歡迎光臨
每天分享高質量文章

[iOS]動態修改app 圖示(icon)

作者:流火緋瞳

連結:https://www.jianshu.com/p/69313970d0e7

動態修改app的圖示,就是在不重新安裝app的情況下,可以修改當前的icon圖示;在某些情況下,是有這個需求的;例如,可以更換主題的app中,一般都會有一套完整的主題包含相應的icon;還有就是一些節日主題的icon或者促銷的icon,例如淘寶、京東等的節日icon。

在iOS 10.3之後,蘋果官方提供了相關的API來實現這個功能,主要是下麵這幾個方法:


@interface UIApplication (UIAlternateApplicationIcons)
// 如果為NO,表示當前行程不支援替換圖示
@property (readonlynonatomicBOOL 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 (nullablereadonlynonatomicNSString *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放在一個檔案夾內:

其檔案夾內是這樣的

這裡每種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 方式開啟,新增以下程式碼:


<key>CFBundleIconskey>
    <dict>
        <key>CFBundleAlternateIconskey>
        <dict>
            <key>rainkey>
            <dict>
                <key>CFBundleIconFileskey>
                <array>
                    <string>rainstring>
                array>
                <key>UIPrerenderedIconkey>
                <false/>
            dict>
            <key>snowkey>
            <dict>
                <key>CFBundleIconFileskey>
                <array>
                    <string>snowstring>
                array>
                <key>UIPrerenderedIconkey>
                <false/>
            dict>
            <key>sunshinekey>
            <dict>
                <key>CFBundleIconFileskey>
                <array>
                    <string>sunshinestring>
                array>
                <key>UIPrerenderedIconkey>
                <false/>
            dict>
            <key>cloudykey>
            <dict>
                <key>CFBundleIconFileskey>
                <array>
                    <string>cloudystring>
                array>
                <key>UIPrerenderedIconkey>
                <false/>
            dict>
        dict>
        <key>CFBundlePrimaryIconkey>
        <dict>
            <key>CFBundleIconFileskey>
            <array>
                <string>string>
            array>
            <key>UIPrerenderedIconkey>
            <false/>
        dict>
        <key>UINewsstandIconkey>
        <dict>
            <key>CFBundleIconFileskey>
            <array>
                <string>string>
            array>
            <key>UINewsstandBindingTypekey>
            <string>UINewsstandBindingTypeMagazinestring>
            <key>UINewsstandBindingEdgekey>
            <string>UINewsstandBindingEdgeLeftstring>
        dict>
    dict>

如果是添加了多個尺寸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,即:

但是,在測試中發現,使用上面的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

這樣在切換圖示的時候就沒有系統的彈框了:

參考文章

iOS 10.3 如何更換 app 圖示



編號303,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類微信公眾號

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂