如何悄悄更改 iOS App icon
有的時候因為要做些壞壞的事、或者給客戶驚喜,我們常常會接到一個需求「希望在不更新 App 的狀態下,更換 icon」。
此篇就來介紹如何更換 App Icon,以及更進階版的更換 icon 不跳出系統彈窗。
備註: 目前這個功能只能支援 iOS 10.3 以上
更換 icon 總共分為三個步驟:
- 將 icon 圖檔放入 project 內
- 新增 icon 資料在 info.plist 內
- 呼叫
setAlternateIconNam
- method swizzling 達成悄悄更換
將 icon 圖檔放入 project 內
首先需要準備 120x120 的 2x、3x 圖檔,如果是要更換 ipad 的 icon 的話,會需要 76x76的2x、3x圖檔,接著將檔案放入專案資料夾內,如下圖。
新增 icon 資料在 info.plist 內
在你專案的 info.plist 上點選 Open As -> Source Code
新增底下這段 code (範例為兩個可替換icon)
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>appIcon1</key> //這邊放你設定的icon name(使用系統API時會用到)
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>appIcon1</string> //這邊放你的icon檔名
</array>
</dict>
<key>appIcon2</key> //這邊放你設定的icon name(使用系統API時會用到)
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>appIcon2</string> //這邊放你的icon檔名
</array>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
若需要替換 ipad 的 icon 的話,則需要再新增以下代碼,原理一樣。
<key>CFBundleIcons~ipad</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>ipadAppIcon1</key> //這邊放你設定的icon name
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>ipadAppIcon1</string> //這邊放你的icon檔名
</array>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
呼叫系統的 setAlternateIconName
// 先確認是否可換 icon
guard UIApplication.shared.supportsAlternateIcons else { return }
// 設定你要替換的 icon 名稱
let iconName = "appIcon1"
// 執行 setAlternateIconName
UIApplication.shared.setAlternateIconName(name, completionHandler: { (error) in
if let error = error {
print("failed")
} else {
print("App icon changed successfully, iconName: \(name)")
}
})
備註:
呼叫 setAlternateIconName 必須要在 main thread,如果更換一直失敗的話,建議可以延遲 0.5秒
iPad 只能更換 iPad 的 icon,iPhone 只能更換 iPhone 的,圖檔不能混用
知道怎麼更換 icon 了,那如何悄悄更換呢?
由於呼叫 setAlternateIconName 這個系統 API 會跳出彈窗,如下
這個其實蠻煩人的,所以我們在這邊如果要消除這個系統彈窗,就必須使用 method swizzling 的方式。
首先先建立 UIViewController、DispatchQueue Extension
最後在 AppDelegate 的 didFinishLaunchingWithOptions 加上這段
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// 若 alert title&message 都是 nil 則讓 alert 不出來UIViewController.runtimeReplaceAlert()return true}
但使用這個方法需要注意,如果你也有 alert 是 title、message 都是 nil 的話,你的這個 alert 也將會失效。
以上。