Changing your iOS App Icon programmatically
Improving user experience will always help to retain users.
As our applications evolve, we may find ourselves wanting to update our app's brand to show a real evolution. This usually means updating our app's icon.
A simple task. But as little as it seems, every change we make in our app could be the difference between a recurrent and a lost user. We could take this opportunity, and create something enjoyable.
In this article, I want to show you how you can take a small change like this, and transform it into a richer experience.
Configuration
Once you have your new App Icon set ready, import it to Xcode with a different name.
- I named my new set
AppIcon-Update-1
. If in the future I change the icon, I can name itAppIcon-Update-2
and so on.
- I also included a snapshot of the Icon to display them in a view as an Image.
Now, we will need to include both App Icon sets in the application’s binary. To do this, go to your target’s build settings and change the property Include All App Icon Assets
to Yes.
To change our app’s icon, we must call UIApplication.shared.setAlternativeIconName(_:) async throws
. If we pass nil
as a parameter, the app will restore the original App Icon.
Settings
We want to present our new App Icon, but we also want to give our users the possibility to choose which icon they want to use.
Create a new enum
that holds all the icon information we’re going to need.
enum AppIcon: CaseIterable {
case `default`
case updateOne
var name: String? {
switch self {
case .default:
return nil
case .updateOne:
return "AppIcon-Update-1"
}
}
var description: String {
switch self {
case .default:
return "Default"
case .updateOne:
return "Update 1"
}
}
var icon: Image {
switch self {
case .default:
return Image("AppIcon-Icon")
case .updateOne:
return Image("AppIcon-Update-1-Icon")
}
}
}
extension AppIcon {
init(from name: String) {
switch name {
case "AppIcon-Update-1": self = .updateOne
default: self = .default
}
}
Now we can create a simple settings view where users can choose between the different icon options.
struct SettingsView: View {
/// State properties
@State private var selectedIcon: AppIcon = .default
var body: some View {
Form {
Section(
header: Text("App Icon").font(.headline),
footer: Text("You can customize the app icon to fit in with your home theme")
) {
ForEach(AppIcon.allCases, id: \.self) { icon in
Toggle(isOn: Binding(
get: { selectedIcon == icon },
set: { newValue in
if newValue {
selectedIcon = icon
updateIcon()
}
}
), label: {
HStack {
icon.preview
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50)
.clipShape(RoundedRectangle(cornerRadius: 10))
Text(icon.description)
.font(.title3)
}
})
.tint(Color.accentColor)
}
}
}
.onAppear {
getCurrentIcon()
}
}
}
// MARK: - Helpers
private extension SettingsView {
func getCurrentIcon() {
if let iconName = UIApplication.shared.alternateIconName {
selectedIcon = AppIcon(from: iconName)
} else {
selectedIcon = .default
}
}
func updateIcon() {
Task {
await CommonUtils.updateAppIcon(with: selectedIcon.name)
}
}
}
// -------
class CommonUtils {
static func updateAppIcon(with iconName: String?) async {
Task {
do {
guard UIApplication.shared.alternateIconName != iconName else {
return
}
try await UIApplication.shared.setAlternateIconName(iconName)
} catch {
print("Could not update icon \(error.localizedDescription)")
}
}
}
}
If your app supports light & dark mode, this is a cool feature you can add with almost no effort. Just create a new App Icon Set for your dark mode and add it to the AppIcon
enum.
Animating the change
We’re presenting a significant update to our users (updating the icon is not a small deal), we should give it the relevance that it deserves, right?
All the configuration we have done before was the foundation to update the app’s icon. But we don’t have to stop there. Here is where our creativity comes into the game (the fun stuff 😉).
For our demo app, right after users update the app, I want to show them that a new icon is available. So I created a simple view to present the change in a “gaming” way.
The source code is available here if you like to check it out.