Alternate App Icon in Xcode
Allowing your users to swap out their app icon is a fantastic way to let them personalize their home screen. Whether it's a sleek dark mode variant or a completely fresh thematic style, providing options makes your app feel more integrated into a user's aesthetic.
While iOS has supported this since version 10.3, the "old way" involved a headache of manual Info.plist entries.Thankfully, modern Xcode makes this process much smoother.
1. Organizing Your Assets
The first step is adding your new icon sets to the Asset Catalog. You can create a new set or duplicate your existing one.
Pro Tip: To make the UI implementation easier later, I recommend adding a -Preview version of each icon to your assets. This allows you to show the user exactly what they are choosing before they commit to the change.2. Tuning Xcode Build Settings
Once your images are ready, you need to tell Xcode to actually include these alternative sets in the final app bundle.
In your project’s Build Settings, look for "Include All App Icon Assets." While you can set this to "Yes," I prefer the more explicit "Alternate App Icon Sets" setting. By manually listing your sets here, you avoid bloating your app with old or unused icons that might still be sitting in your folders.
3. The Implementation: Swift & SwiftUI
To keep our code clean, we’ll start with a robust enum. This maps our asset names to readable descriptions and handles the logic for fetching preview images.
enum AppIcon: String, CaseIterable, Identifiable {
case primary = "AppIcon"
case darkMode = "AppIcon-Dark"
var id: String { rawValue }
// Returning nil resets the icon to the default system icon
var iconName: String? {
self == .primary ? nil : rawValue
}
var description: String {
switch self {
case .primary: return "Default"
case .darkMode: return "Dark Mode"
}
}
var preview: UIImage {
UIImage(named: rawValue + "-Preview") ?? UIImage()
}
}Creating the View Model
We’ll use an ObservableObject to track which icon is currently active. This connects the system's state to our UI.
final class AppIconManager: ObservableObject {
@Published private(set) var currentIcon: AppIcon
init() {
let name = UIApplication.shared.alternateIconName
currentIcon = AppIcon(rawValue: name ?? "") ?? .primary
}
func updateIcon(to icon: AppIcon) {
let previous = currentIcon
currentIcon = icon
Task { @MainActor in
guard UIApplication.shared.alternateIconName != icon.iconName else { return }
do {
try await IApplication.shared.setAlternateIconName(icon.iconName)
} catch {
print("Failed to change icon: \(error.localizedDescription)")
currentIcon = previous // Rollback on failure
}
}
}
}Building the Selection UI
Finally, we can build a simple SwiftUI list that lets users tap to switch. Keep in mind that when the icon changes, iOS will automatically trigger a system alert—this is a native security feature and cannot be disabled.
A Quick Note on Automation
If you're finding tools like Ruby or Fastlane to be a bit of a setup nightmare, it’s worth looking into the Codemagic CLI tools. While it's not a 1:1 replacement for every Fastlane feature (like screenshot generation), it’s a lightweight, open-source alternative for building, provisioning, and publishing your apps without the usual installation friction.
Wrapping Up
Giving users control over their home screen is a small touch that goes a long way. With Xcode’s modern settings and a clean Swift enum, it’s easier than ever to manage.