Issue #749

Some apps want to support alternative app icons in Settings where user can choose to update app icon. Here’s some must do to make it work, as of Xcode 12.2

  • In Info.plist, must declare CFBundleIcons with both CFBundlePrimaryIcon and CFBundleAlternateIcons
  • Icons must be in project folder, not Asset Catalog

Here’s how it is done on my app PastePal

Add app icons to project folder

Prepare icons, like Icon1, Icon2 with 2 variants for 2x and 3x. These need to be added to project folder. When I add these to Asset Catalog it does not update app icon. I usually add a new folder in project like Resource/AlternateAppIcons

The default 1x size for iPhone icon size from iOS 7 to iOS 14 is 60px.

Declare in Info.plist

Although declaring CFBundlePrimaryIcon seems unnecessary, I find that without this it does not work. I use AppIcon60x60 as the compiled one from Asset Catalog for our main AppIcon

For UIPrerenderedIcon, a boolean value indicating whether the app’s icon already contains a shine effect. We set to false to allow iOS to apply round and glossy effect to our icon.

<key>CFBundleIcons</key>
<dict>
    <key>CFBundlePrimaryIcon</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>AppIcon60x60</string>
            </array>
            <key>UIPrerenderedIcon</key>
            <false/>
        </dict>
    <key>CFBundleAlternateIcons</key>
    <dict>
        <key>AppIconPride1</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>AppIconPride1</string>
            </array>
            <key>UIPrerenderedIcon</key>
            <false/>
        </dict>
        <key>AppIconPride2</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>AppIconPride2</string>
            </array>
            <key>UIPrerenderedIcon</key>
            <false/>
        </dict>
    </dict>
</dict>

Asset Catalog

Since we’re using Asset Catalog, if we simply use UIImage with named, it will load by default in Asset Catalog, unless we manually specify bundle path. For simple demo, we can just copy our images again to Asset Catalog so we can show in the app

I usually have an enum of AlternateAppIcon so I can display in a grid and let user choose

enum AlternateAppIcon: String, CaseIterable, Identifiable {
    var id: AlternateAppIcon { self }

    case main = "Main"
    case pride1 = "Pride1"
    case pride2 = "Pride2"
}

func onChange(_ icon: AlternateAppIcon) {
    guard UIApplication.shared.supportsAlternateIcons else { return }
    switch icon {
    case .main:
        UIApplication.shared.setAlternateIconName(nil)
    default:
        UIApplication.shared.setAlternateIconName(icon.name)
    }
}

Change app icon for iPad

So far we’re only talk about iPhone. To support iPad, we need to specify iPad versions in Info.plist with CFBundleIcons~ipad

- CFBundleIcons
  - CFBundleAlternateIcons
    - Icon Name
      - CFBundleIconFiles
- CFBundleIcons~ipad
  - CFBundleAlternateIcons
    - Icon Name
     - CFBundleIconFiles

Also notice the size for icons on iPad