Generating App Icons with SwiftUI

Zac White
Zac White
Apr 27, 2020 · 4 min read
Image for post
Image for post

SwiftUI is an incredibly powerful UI building tool. It has limitations, but it brings a lot of new and interesting concepts to the table. One of those new concepts is that it not only provides UI primitives like Text, Image and Picker (to name just a few), it also provides drawing primitives like Path, Rectangle, Circle, etc. So now instead of digging down to CoreGraphics, SwiftUI provides an appealing alternative to mix UI and custom drawing together.

We can take advantage of that drawing ability to generate our app Icon and leverage the benefits of the built-in SwiftUI previewing system to get live, updating previews of our code-based icon 🎉

How to integrate into your project

Check out the project over on GitHub for the latest instructions, but the basic outline is:

  1. Download and expand the latest release zip and drag the Icon folder into the root of your project, copying the files into the project, creating a group and adding the files to your App target.
  2. Un-include the generate.swift and IconGenerator.swift files from your App’s target since those are only going to be run from the Run Script build phase and won’t compile as part of your app.
  3. Add a Run Script build phase before your Copy Resources phase and specify the path to Icon.swift as the first Input File:

Now you should be able to add your drawing code to the Icon struct’s body property and get all the benefits of live-updating from SwiftUI. And every time you build and run, you’ll get your new icon generated for all the appropriate sizes.

Image for post
Image for post

Previewing your App icon

We can even use some helpers in the included Icon+PreviewHelpers.swift to generate a live preview of the app icon…on a simulated home screen!

Image for post
Image for post

How does this work?

In order to generate an icon, we have to essentially render a SwiftUI View into a hosting view, resize the view, create bitmaps for each of those view sizes and insert those into an AppIcon.appiconset inside the app’s Assets.xcassets. One of the benefits of using SwiftUI will be that we can render the View at different sizes first and generate a new bitmap from each of those instead of just scaling a bitmap. Yay, vectors! SwiftUI even does some tricks under-the-hood to pixel fit your shapes or text to whatever pixel size you are representing, so the bitmaps at smaller scales should look as good as possible.

Then, to render these bitmaps as a build step, we can use AppKit’s implementation of SwiftUI (in Catalina only) to render the Views from the command-line using a Swift script that ‘imports’ your Icon. So in your iOS target, you will have an Icon.swift that is shared between the Run Script phase and the iOS target, but all the other helper code will just be used by the Run Script phase.

Generating the Icon during Builds

The main generate.swift script that will run in your build is fairly simple and can check the build environment for TARGETED_DEVICE_FAMILY in order to generate only the necessary icons:

Then you’ll need to actually execute the script as a Build Phase (see Step 3 of Quick Setup above), which is made slightly more complicated by the fact that we need to smush together several swift files in order to run this as one ‘script’.

Now when you re-build, you get your new icon set automatically generated and based on whatever device families (iPad or iPhone) you have selected in your project. While not currently supported here, it wouldn’t be terribly difficult to add support for macOS, watchOS, tvOS, etc. Reach out if you do!

The end-result should now be a fully generated icon using SwiftUI drawing primitives. Now you can even embed Icon() into your app’s UI alongside all your other SwiftUI views!

Next Steps

This is a far from perfect setup. In fact, I’d go as far as to say it’s a bit of a hack. Ideally we’d be able to include this script as easily as a dependency, but because the icon has to be both included in your app and compiled on the build system, we have to jump through some hoops.

We’ve been using this in an upcoming product and are loving the flexibility and ease of expressing your app’s icon as a just another view.

We’re always open to feedback, so feel free to reach out if you have some ideas!

Velos Mobile

We are a group of technologists who are passionate about…

Zac White

Written by

Zac White

Chief  Platforms Developer and Co-founder of https://medium.com/velos. 👷‍♂️🏗📱⌚️📺💻

Velos Mobile

We are a group of technologists who are passionate about creating excellent mobile experiences. We’ve been doing this for a long time, and we love sharing our expertise from the first wireframe to the last bug. Check us out at www.velosmobile.com

Zac White

Written by

Zac White

Chief  Platforms Developer and Co-founder of https://medium.com/velos. 👷‍♂️🏗📱⌚️📺💻

Velos Mobile

We are a group of technologists who are passionate about creating excellent mobile experiences. We’ve been doing this for a long time, and we love sharing our expertise from the first wireframe to the last bug. Check us out at www.velosmobile.com

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store