Its gradually getting more common to see apps offering alternate icons, and its always been pretty easy to do. The only problem is that it was really easy to mess up - lots of manually generated files and entries in a plist. Thanks to a change in Xcode 13, you can drop the plist and speed up adding new icons.

To get started open up your apps build settings, select all and combined, then search for “Asset Catalog Compiler - Options”. Enable “Include All App Icon Assets”. If you’re curious what this does, xcode will now add the needed keys and values to your plist for each app icon you provide, instead of you having to do it all manually.

02-asset-catalogue-alternate-icons-images/01.png

Next, open up your asset catalogue and drag in a new app icon file, with a different name. In this case, i’ve just called it “AlternateIcon”.

02-asset-catalogue-alternate-icons-images/02.png

The code to set an app icon is incredibly simple. To set it back to the original, just pass nil for the icon name.

let iconName = "AlternateIcon"
UIApplication.shared.setAlternateIconName(iconName, completionHandler: { (err) in
    if err != nil {
        // Show the user an alert
    }
    // Apple shows a confirmation for you
})

One thing to bear in mind - if you want to display these icons in your app, you’ll have to use UIImage. UIImage(named: "name") is capable of returning your AppIcons, but Image("name") is not. The easy way around this is just to use a wrapper, like this:

enum AppIcon: String, CaseIterable {
    case standard = "Default"
    case alternate = "Alternate"
    
    /// The name that can be passed to `setAlternateIconName`
    var iconName: String? {
        switch self {
        case .alternate:
            return "AlternateIcon"
        default:
            return nil
        }
    }
    
    /// The actual asset, which will fallback to the normal AppIcon if anything is missing.
    var icon: UIImage {
        return UIImage(named: iconName ?? "AppIcon") ?? UIImage()
    }
}

// Which can be used like...
Image(uiImage: AppIcon.alternate.icon)
    .resizable()

It’s that easy!

I’ve put together a quick sample app, so you can see how this works in action.

02-asset-catalogue-alternate-icons-images/03.png

You can grab this from my code samples repo.