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

動態更換App圖標這件事,在用戶里老是存在需求的:有些用戶喜歡「美化」本身的手機。至於用戶們喜歡美化到什麼程度,這得看我的需求。有的用戶想定製個性的App圖標,那麼各大iPhone論壇裏都有方法能夠不越獄更改App圖標;有的用戶想讓App圖標「動」起來(如系統應用時鐘),那麼不越個獄還真很差辦。html

不過今天咱們想談談蘋果官方對於動態更換App圖標的支持。ios

本系列文章

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

Demo演示

DynamicAppIconDemo1

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

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

Demo中能夠看到,在不從新安裝App的狀況下,能夠實現更新App的圖標。可是會彈出一個提示,告知用戶當前圖標已更換,固然下一篇文章將會突破這個「限制」。objective-c

該功能應用的場景

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

二、各種皮膚主題(淘寶就可換膚),附帶App圖標一塊更換。數組

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

四、圖標促銷提示,如淘寶京東特定節日:11.十一、6.18,提早更換App圖標。數據結構

固然該功能(API)當前只支持iOS10.3以上的系統,因此只能當作一項附加功能來進行使用。下面將詳細講解下如何使用代碼來實現此功能。app

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

supportsAlternateIcons Document

(翻譯)只有系統容許改變你的app圖標時該值才爲YES。你須要在Info.plist文件中的CFBundleIcons這個鍵內聲明可更換的app圖標。

  1. alternateIconName

alternateIconName Document

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

  1. setAlternateIconName:completionHandler:

setAlternateIconName Document

(翻譯)alertnateIconName參數:該參數爲須要更換的app圖標名字,是在你的Info.plist中的CFBundleAlertnateIcons鍵裏定義的。若是你想顯示的是用CFBundlePrimaryIcon鍵所定義的主圖標的話,就傳入nil。CFBundleAlertnateIcons與CFBundlePrimaryIcon鍵都是在CFBundleIcons裏面定義的。

(翻譯)completionHandler參數:該參數用來處理(更換)結果。當系統嘗試更改app的圖標後,會將結果數據經過該參數傳入並執行(該執行過程是在UIKit所提供的隊列執行,並不是主隊列)。該執行過程會攜帶一個參數:error。若是更換app圖標成功,那麼這個參數就是nil。若是更換過程當中發生了錯誤,那麼該對象會指明錯誤信息,而且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圖標的配置方法

官方配置文檔

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
                                   }
             };複製代碼

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是這樣子的:

Info.plist1

固然也要拖入對應的App圖標:

各類天氣App圖標

不過這裏咱們好像還少配置了App主圖標,也就是正常狀況下咱們的圖標。按照文檔所說,咱們須要在CFBundleIcons裏面配置CFBundlePrimaryIcon這個主圖標對應的內容,可是實際上,咱們仍是按照老方法,在Assets.xcassets中配置AppIcon,對應尺寸填上對應圖片便可。爲何這樣子就能夠配置主圖標呢?讓咱們來看看某知名電商的ipa(在AppStore上下載的包)內的Info.plist(位於Payload/XXXXXX/Info.plist):

知名電商的Info.plist

固然你也能夠在你本身App打出的包內進行查看,系統實際上是會將Assets.xcassets中配置的AppIcon轉化爲Info.plist中的CFBundlePrimaryIcon。因此咱們主圖標的配置方式仍是與原先同樣。

其餘注意事項:

  • 文件擴展名,如@2x,@3x,要麼統一不寫,那麼系統會自動尋找合適的尺寸。要寫就須要把每張icon的擴展名寫上,和上圖的格式同樣,在本系列文章的Demo中也有一個單獨的Demo示例如何添加多尺寸icon。
  • iPad版本若是須要有更換的圖標,須要在CFBundleIcons〜ipad一樣設置一次。

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

全部尺寸圖標

打開DynamicAppIcon(帶尺寸)這個Demo。該Demo中,咱們在各個尺寸的圖標右上角打個」標記「,而後使用上文介紹的setAlternateIconName:completionHandler:進行圖標更換。更換圖標的同時,咱們再作一件事:

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

這裏咱們發送了一個本地通知,一會咱們就能看到通知上顯示的是什麼圖標了:

本地推送圖標對比

再讓咱們去Settings裏面觀察下App圖標:

設置界面圖標對比

看到圖標的區別,也就說明了咱們在Info.plist裏面設置的多尺寸圖標生效了:

多尺寸Info.Pilst

下一篇

在這篇文章裏,你能看到App圖標在運行時被更換了,可是更換的時候會給出一個「擾人」的彈框,該彈框是蘋果爸爸默認加上去的,下一篇就是告訴各位,如何反抗爸爸:去除更換App圖標時的彈框。
iOS動態更換App圖標(二):無彈框更換App圖標(掘金地址)

相關文章
相關標籤/搜索