How to show the app icon and version in a SwiftUI view

Sponsored
RevenueCat logo
Relax, you can roll back your mobile release

No one is immune from shipping critical bugs to production, but Runway helps you limit the amount of havoc that can cause.

Displaying the app icon and version in your app is a great way to provide users, both internal (e.g. testers or stakeholders) and external, with a quick and easy way to identify both which version and variant of the app they are using.

In this article, I will show you how you can create an accessible SwiftUI view that does exactly that and look great for all text sizes and appearances:

App version information view

Getting the app icon

The first step to building the view is to get the app icon from the main bundle. This can be done, as this answer in Stack Overflow shows, by retrieving the values for a set of keys in the app’s Info.plist file:

AppIconProvider.swift
import Foundation

enum AppIconProvider {
    static func appIcon(in bundle: Bundle = .main) -> String {
        # 1
        guard let icons = bundle.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any],
              # 2
              let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
              # 3
              let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
              # 4
              let iconFileName = iconFiles.last else {
            fatalError("Could not find icons in bundle")
        }

        return iconFileName
    }
}

Let’s go through the code above step by step:

  1. We then retrieve the value for the CFBundleIcons key in the Info.plist file. This value is a dictionary containing nested dictionaries with information about the app’s icons.
  2. We then retrieve the value for the CFBundlePrimaryIcon key in the CFBundleIcons dictionary. This value is a dictionary containing information about the app’s primary icon.
  3. We then retrieve the value for the CFBundleIconFiles key in the CFBundlePrimaryIcon dictionary. This value is an array containing the names of the app’s icon files. These names can be used to create a named UIImage using the UIImage(named:) initialiser.
  4. Finally, we retrieve the last value in the CFBundleIconFiles array.

Getting the app version

Now that we have the app icon, let’s retrieve the app version string. Similarly to what we did earlier, we need to read the value for the CFBundleShortVersionString key in the app’s Info.plist:

AppVersionProvider.swift
import Foundation

enum AppVersionProvider {
    static func appVersion(in bundle: Bundle = .main) -> String {
        guard let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String else {
            fatalError("CFBundleShortVersionString should not be missing from info dictionary")
        }
        return version
    }
}

If you want to include the build number alongside the version number in the view we will create in the next section, you can retrieve the value for the CFBundleVersion key instead.

Creating a SwiftUI view

Let’s now put everything together and create a SwiftUI view that shows the app icon and version side by side:

AppVersionInformationView.swift
import SwiftUI

struct AppVersionInformationView: View {
    # 1
    let versionString: String
    let appIcon: String

    var body: some View {
        # 2
        HStack(alignment: .center, spacing: 12) {
            # 3
            // App icons can only be retrieved as named `UIImage`s
            // https://stackoverflow.com/a/62064533/17421764
            if let image = UIImage(named: appIcon) {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .clipShape(RoundedRectangle(cornerRadius: 8))
            }
            # 4
            VStack(alignment: .leading) {
                Text("Version")
                    .bold()
                Text("v\(versionString)")
            }
            .font(.caption)
            .foregroundColor(.primary)
        }
        # 5
        .fixedSize()
        # 6
        .accessibilityElement(children: .ignore)
        .accessibilityLabel("App version \(versionString)")
    }
}

Let’s go through the code above step by step:

  1. The view takes two parameters: the app version and the app icon. These values are passed through to the view using the two providers we created earlier.
  2. We display the app icon and version in a horizontal stack with a spacing of 12 points.
  3. We display the app icon in an Image view. However, app icons can only be retrieved as named UIImages, so we’ll have to create a UIImage first and then convert it into a SwiftUI Image.
  4. We then display the app version in a vertical stack composed of a label with the text version and the app version string itself.
  5. We use the fixedSize() modifier to ensure that both the app icon and VStack views are the same height.
  6. Finally, we group all child views into a single accessibility element and give it a label to provide a better experience for VoiceOver users.

The result of what we have done so far is a view that looks great for all text sizes:

A set of previews at different accessibility sizes

Finally, we can put all elements we created in this article together and display the new version information view in our app like this:

ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        AppVersionInformationView(
            versionString: AppVersionProvider.appVersion(),
            appIcon: AppIconProvider.appIcon()
        )
    }
}