iOS 10.3 Alternate Icons: what can you do and how it works ?

In the first beta of iOS 10.3, Apple introduced the ability for an application to change its icon. You could ask when it would be useful. In fact, I see different cases:

  • In a game, when you want to show a major achievement.
  • With meta applications. For instance: you make an application for universities. When the user logged into its university: you change the app icon.
  • When users bought the “premium in app pack”, you maybe want to remove the “free” label from the icon.
  • To add some seasonality (a.k.a. your app icon with a Christmas hat).

As always, Apple secured the process. Indeed, imagine that you can change your icon for the icon of another app … So, you can only use a finite set of icons that you have included into the applications bundle. This set of icons will be checked by Apple during the App Store review process. Once your app is approved, you will only be able to use one of those validated icons.

Furthermore, you cannot change the icon unbeknownst to the user. Indeed, when you change the icon, there is an alert saying You have changed the icon for "Application Name". Here is a little demonstration of this feature in action:


How it works

To show how this works, I made a dummy supporter application. You have to say which is your favorite national sports team, and it changes the app icons with theses colors. You can find the source code here on Github. So, how is it done ?

Declare

First: you should declare all alternate icons in the info.plist file. The problem is that you should give up assets catalog for icons. Indeed, it seems not to be compatible with this feature :/. So, we should go back to the old method with simple .png resources. Everything is declared in CFBundleAlternateIcons. In this demo, it gives:

<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>de</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>ic_de</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>fr</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>ic_fr</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>it</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>ic_it</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>ic_none</string>
</array>
</dict>
</dict>

We defined 3 alternate icons:

  • de (which is bound to file ic_de)
  • fr (which is bound to file ic_fr)
  • it (which is bound to file ic_it)

And we have the primary icon (the default one) bound to file ic_none.

Change

Once the icons are declared, we simply have to call setAlternateIconName(_:completionHandler:) on UIApplication shared instance with one of the declared icon names. For instance, if we want it icon:

UIApplication.shared.setAlternateIconName("it") { (error) in
if let error = error {
print("err: \(error)")
}
}

Read

If you want to know which icon is currently set up, just read alternateIconName on UIApplication shared instance:

if UIApplication.shared.alternateIconName == "it" {
print("Viva italia")
} else if UIApplication.shared.alternateIconName == "fr" {
print("Allez les bleus!")
}

Future

Right now, this feature is still beta. So it might evolve in the future. Maybe Apple will allow the user to block the icon change (right now, the user is just informed, he cannot say no). Moreover, Apple did not say what is allowed, and what is not in the customization of icons.