modemlooper avatar
About Blog

Alternate App Icon in Xcode

4 min read

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.