How to Change Your App’s Icon in SwiftUI

Let your users set an alternate icon programmatically

Anupam Chugh
Jan 31 · 6 min read
Photo by William Hook on Flickr

The ability to change your app’s icon programmatically has been around for quite a few years. Specifically, this feature was released in iOS 10.3, and it allows developers to switch between a predefined set of alternate icons.

Dynamic icons are useful when your application is based on subscriptions. Tinder is one application that uses this feature beautifully as it gives Tinder Gold members an option to switch the icon.

Our goals

  • We’ll leverage SwiftUI Pickers to allow the user to choose their favorite icon from a menu list.
  • Finally, we’ll address a serious pitfall. Pickers and NavigationView don’t get along the way we want them to currently — and we’ll see why.

Setting Alternate App Icons Programmatically

Get the alternate app icon

UIApplication.shared.alternateIconName

Set alternate icon

UIApplication.shared.setAlternateIconName(iconName, completionHandler: {error in})

But where do we set the icon name? We’ll come back to this in a bit.

The following are the rules you need to follow when using alternate icons in your application:

1. Don’t add alternate icons in the assets catalogue

2. Handle the Info.plist file carefully

The following snippet shows the dictionary structure for the CFBundleIcons key. Add this at the top level of the XML dictionary that you see.

It might look a bit scary at first, but it's pretty straightforward. CFBundleIcons holds two dictionaries:

  • CFBundlePrimaryIcon for the primary icon that resides in your asset catalogue
  • CFBundleAlternateIcons is used to hold the alternate icons. The keys inside the CFBundleAlternateIcons represents the name you’ll use in the code. The name goes in place of the iconName we saw earlier.
  • Inside CFBundleIconFiles, we pass the icon file names — without extensions and without the 2x and 3x variants. Just the names.
  • UIPrerenderedIcon is a boolean key that indicates the gloss effect. Set this to false to let the system add the shine effect on your icon.

Project Structure


Decoding the Alternate-Icons Dictionary

iconNames is the array of strings that are defined in the ObservableObject class below with the getAlternateIconNames function called in the init method:

class IconNames: ObservableObject {
var iconNames: [String?] = [nil]
@Published var currentIndex = 0

init() {
getAlternateIconNames()

if let currentIcon = UIApplication.shared.alternateIconName{
self.currentIndex = iconNames.firstIndex(of: currentIcon) ?? 0
}
}
  • In the above code, the first element of the iconNames array is set as nil as an indicator of the primary app icon.
  • The active icon’s index is set as a @Published property wrapper. It’s initialized with the currently active icon.

We’ll share the above data model with our SwiftUI ContentViews through@EnvironmentObject, which is passed to the view hierarchy from the SceneDelegate.

window.rootViewController = UIHostingController(rootView: contentView.environmentObject(IconNames()))

Setting Up Our SwiftUI Picker in Our ContentView

  • Whenever the Picker’s selection is changed, the onReceive modifier gets triggered. It publishes the latest value it got, (index of the selected icon).
  • Inside the closure, we’re comparing the icon name of the new selection with the currently active app icon’s name. This is a crucial step since it triggers an icon change only when the user chooses a different one.

Here’s a look at our application in action:

Output

As we can see above, when the alternate icon is changed successfully, the system sends an alert. Hence, it’s important to call the setAlternateIconName from the main thread once the view is set.

Now, let’s look at how to set the alternate icons in the SwiftUI view and also address an issue when Pickers and the NavigationView operate together.


SwiftUI Picker and NavigationView Pitfall

Pitfall 1

Now we have can address the overlay issue by setting a button style on the NavigationView, as shown in this piece. But then, we lose our SwiftUI Picker selection indicator:

Remedy

So we finally got our application working with alternate icons displayed in a SwiftUI Picker.


Pitfall 2

Remedy


Conclusion

Also, we addressed two common pitfalls when using NavigationView with Pickers in SwiftUI. The issues caused overlay colors inside its child views and looked at ways to work around it.

The full source code of this piece is available in this Github repository.

That’s it for this one — thanks for reading.

Better Programming

Advice for programmers.

Anupam Chugh

Written by

iOS Developer exploring the depths of ML and AR on Mobile. Loves writing about thoughts, technology and code. Blogging weekly at iowncode.com

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade