【iOS 開發】iOS 10.3 如何更換 app 圖示

從來吃不胖發表於2019-02-26

動態更換App圖示這件事,在使用者裡總是存在需求的:有些使用者喜歡“美化”自己的手機。至於使用者們喜歡美化到什麼程度,這得看個人需求。有的使用者想定製個性的App圖示,那麼各大iPhone論壇裡都有方法可以不越獄更改App圖示;有的使用者想讓App圖示“動”起來(如系統應用時鐘),那麼不越個獄還真不好辦。

不過今天我們想談談蘋果官方對於動態更換App圖示的支援。

本系列文章

  1. iOS動態更換App圖示(一):基礎使用
  2. iOS動態更換App圖示(二):無彈框更換App圖示
  3. iOS動態更換App圖示(三):動態下載App圖示進行更換

Demo演示

【iOS 開發】iOS 10.3 如何更換 app 圖示
DynamicAppIconDemo1

Demo地址:github.com/maybeisyi/C…

本篇文章對應工程為:DynamicAppIcon(一)

Demo中可以看到,在不重新安裝App的情況下,可以實現更新App的圖示。但是會彈出一個提示,告知使用者當前圖示已更換,當然下一篇文章將會突破這個“限制”。

該功能應用的場景

1、白天/夜間模式切換,在切換App主色調同時切換App圖示。

2、各類皮膚主題(淘寶就可換膚),附帶App圖示一塊更換。

3、利用App圖示表達某種特定功能,如Demo中的,提示當前天氣。

4、圖示促銷提示,如淘寶京東特定節日:11.11、6.18,提前更換App圖示。

當然該功能(API)當前只支援iOS10.3以上的系統,所以只能當做一項附加功能來進行使用。下面將詳細講解下如何使用程式碼來實現此功能。

API與文件

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複製程式碼

總共3個方法,簡潔明瞭,不過但看這3個API,我們並不清楚alternateIconName是如何與app圖示掛鉤的,所以我們需要進一步翻看文件。

文件

shift+command+0開啟文件,依次檢視3個API,翻譯如下:

  1. supportsAlternateIcons

【iOS 開發】iOS 10.3 如何更換 app 圖示
supportsAlternateIcons Document

(翻譯)只有系統允許改變你的app圖示時該值才為YES。你需要在Info.plist檔案中的CFBundleIcons這個鍵內宣告可更換的app圖示。

  1. alternateIconName

【iOS 開發】iOS 10.3 如何更換 app 圖示
alternateIconName Document

(翻譯)當系統展示的是你更換後的app圖示時,該值即為圖示名字(Info.plist中定義的圖示名字)。如果展示的是主圖示時,這個值為nil。

  1. setAlternateIconName:completionHandler:

【iOS 開發】iOS 10.3 如何更換 app 圖示
setAlternateIconName Document

(翻譯)alertnateIconName引數:該引數為需要更換的app圖示名字,是在你的Info.plist中的CFBundleAlertnateIcons鍵裡定義的。如果你想顯示的是用CFBundlePrimaryIcon鍵所定義的主圖示的話,就傳入nil。CFBundleAlertnateIcons與CFBundlePrimaryIcon鍵都是在CFBundleIcons裡面定義的。

(翻譯)completionHandler引數:該引數用來處理(更換)結果。當系統嘗試更改app的圖示後,會將結果資料通過該引數傳入並執行(該執行過程是在UIKit所提供的佇列執行,並非主佇列)。該執行過程會攜帶一個引數:error。如果更換app圖示成功,那麼這個引數就是nil。如果更換過程中發生了錯誤,那麼該物件會指明錯誤資訊,並且app的圖示保持不變。

【iOS 開發】iOS 10.3 如何更換 app 圖示
setAlternateIconName2 Document

(翻譯)使用該方法改變app圖示為主圖示或者可更換的圖示。只有在supportsAlternateIcons的返回值為YES時才能更換。

(翻譯)你必須在Info.plist檔案的CFBundleIcons鍵裡面宣告可以更換的app圖示(主圖示和可更換圖示)。如果需要獲取關於可更換圖示的配置資訊,請查閱 Information Property List Key Reference 裡面有關CFBundleIcons的描述。

文件中反覆提到了Info.plist檔案與CFBundleIcons,這是Xcode6之前是用來配置App圖示的老方法,後來有了更完備的Assets.scassets,配置App圖示更簡單與完善了。不過如今該方法再次被搬上臺面,在蘋果內部一定也是歷經多次“撕逼”後的結果,為何蘋果急於在10.3而不是11推出該API?為何蘋果不使用Assets.scassets配置可變更的App圖示?我們不得而知,不過相信蘋果後期會對該配置方法做優化的。

可變更App圖示的配置方法

官方配置文件

【iOS 開發】iOS 10.3 如何更換 app 圖示
CFBundleAlternateIcons1 Document

該配置文件的內容較多,我們挑重點羅列下(忽略tvOS部分,下同):

  • Info.plist是個字典,假設為NSDictionary *infoPlist

  • CFBundleIcons是Info.plist字典裡的一個@"CFBundleIcons"

  • CFBundleIcons對應的value是個字典
  • CFBundleIcons裡面能夠包含的鍵有:CFBundlePrimaryIcon、CFBundleAlternateIcons、UINewsstandIcon。

讓我們用程式碼展示下這個繞口的結構:

NSDictionary *infoPlist;
infoPlist = @{
               @"CFBundleIcons" : @{
                                     @"CFBundlePrimaryIcon" : xxx,
                                     @"CFBundleAlternateIcons" : xxx,
                                     @"UINewsstandIcon" : xxx
                                   }
             };複製程式碼

【iOS 開發】iOS 10.3 如何更換 app 圖示
CFBundleAlternateIcons2 Document

這是關於CFBundleAlternateIcons的配置文件:

其中有一句話,不仔細思考很難明白:

In iOS, the value of the key is a dictionary. The key for each dictionary entry is the name of the alternate icon

翻譯:

該鍵對應的值是字典,每個字典條目的鍵都是備用圖示的名稱。

從這句話中無法很快理清CFBundleAlternateIcons下層的資料結構。實際上這句話表達的意思是:

該鍵對應的值是字典,這個字典裡的每一個鍵對應的又是一個個字典,而這些鍵都是備用圖示的名稱。

讓我們把剩餘的重點羅列下:

  • CFBundleAlternateIcons所對應的value是個字典(iOS中),假設為NSDictionary * alertnateIconsDic
  • alertnateIconsDic的鍵,都是備用圖示的名字,假設為@"newAppIcon"@"newAppIcon2"
  • @"newAppIcon"的value是個包含CFBundleIconFiles和UIPrerenderedIcon這兩個鍵的字典
  • CFBundleIconFiles的value是字串或者陣列(陣列內容也為字串)。字串的內容為各尺寸備用圖示的名字。
  • UIPrerenderedIcon的value是BOOL值。這個鍵值所代表的作用在iOS7之後(含iOS7)已失效,在iOS6中可渲染app圖示為帶高亮效果。所以這個值目前我們可以不用關心。

讓我們用程式碼展示下CFBundleAlternateIcons的value的結構:

@"CFBundleAlternateIcons" : @{
                               @"newAppIcon" : @{
                                                 @"CFBundleIconFiles" : @[
                                                                            @"newAppIcon"
                                                                         ],
                                                 @"UIPrerenderedIcon" : NO
                                                },
                               @"newAppIcon2" : @{
                                                 @"CFBundleIconFiles" : @[
                                                                            @"newAppIcon2"
                                                                         ],
                                                 @"UIPrerenderedIcon" : NO
                                                 }
                             }複製程式碼

實際配置檔案(Info.plist)

對照著上述的配置文件,我們實際配置完的Info.plist是這樣子的:

【iOS 開發】iOS 10.3 如何更換 app 圖示
Info.plist1

當然也要拖入對應的App圖示:

【iOS 開發】iOS 10.3 如何更換 app 圖示
各種天氣App圖示

不過這裡我們好像還少配置了App主圖示,也就是正常情況下我們的圖示。按照文件所說,我們需要在CFBundleIcons裡面配置CFBundlePrimaryIcon這個主圖示對應的內容,但是實際上,我們還是按照老方法,在Assets.xcassets中配置AppIcon,對應尺寸填上對應圖片即可。為什麼這樣子就可以配置主圖示呢?讓我們來看看某知名電商的ipa(在AppStore上下載的包)內的Info.plist(位於Payload/XXXXXX/Info.plist):

【iOS 開發】iOS 10.3 如何更換 app 圖示
知名電商的Info.plist

當然你也可以在你自己App打出的包內進行檢視,系統其實是會將Assets.xcassets中配置的AppIcon轉化為Info.plist中的CFBundlePrimaryIcon。所以我們主圖示的配置方式還是與原先一樣。

其他注意事項:

  • 副檔名,如@2x,@3x,要麼統一不寫,那麼系統會自動尋找合適的尺寸。要寫就需要把每張icon的副檔名寫上,和上圖的格式一樣,在本系列文章的Demo中也有一個單獨的Demo示例如何新增多尺寸icon。
  • iPad版本如果需要有更換的圖示,需要在CFBundleIcons〜ipad同樣設定一次。

更換圖示後,如何驗證iPhone上使用了多尺寸的圖示?

【iOS 開發】iOS 10.3 如何更換 app 圖示
所有尺寸圖示

開啟DynamicAppIcon(帶尺寸)這個Demo。該Demo中,我們在各個尺寸的圖示右上角打個”標記“,然後使用上文介紹的setAlternateIconName:completionHandler:進行圖示更換。更換圖示的同時,我們再做一件事:

// 測試推送上是否使用了20尺寸的圖示
UILocalNotification *noti = [[UILocalNotification alloc] init];
noti.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
noti.alertBody = @"我們看看推送上面的App圖示";
[[UIApplication sharedApplication] scheduleLocalNotification:noti];複製程式碼

這裡我們傳送了一個本地通知,一會我們就能看到通知上顯示的是什麼圖示了:

【iOS 開發】iOS 10.3 如何更換 app 圖示
本地推送圖示對比

再讓我們去Settings裡面觀察下App圖示:

【iOS 開發】iOS 10.3 如何更換 app 圖示
設定介面圖示對比

看到圖示的區別,也就說明了我們在Info.plist裡面設定的多尺寸圖示生效了:

【iOS 開發】iOS 10.3 如何更換 app 圖示
多尺寸Info.Pilst

下一篇

在這篇文章裡,你能看到App圖示在執行時被更換了,但是更換的時候會給出一個“擾人”的彈框,該彈框是蘋果爸爸預設加上去的,下一篇就是告訴各位,如何反抗爸爸:去除更換App圖示時的彈框。
iOS動態更換App圖示(二):無彈框更換App圖示(掘金地址)

相關文章