How to incorporate app icon files for iOS into Xcode 14?

It’s been a very long journey on this but I’ve finally got the answer.

Step 1: Create your app icon set.

My way of doing this has been to go into Xcode, go File > New > Asset Catalog. Put it all together with all the icons. Then go find this in Finder and copy the whole asset catalog folder into my project repo. This contains the right structure and also saves you writing the Content.json files.

Note that as of Xcode 14, for iOS you can have a single 1024x1024 image if you’re happy for Xcode to do all the resizing. See online for how to do this. This still generates a structure that can be used as before.

Let’s say your folder structure is: MyAppIcons.xcasset containing AppIcon.appiconset. This means your asset catalog is called MyAppIcons and your app icon set is called AppIcon. This distinction is crucial for getting this to work right.

Step 2: Put the asset catalog name into Info.plist.in

...
    <key>CFBundleIcons</key>
    <dict>
        <key>CFBundlePrimaryIcon</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
            <string>MyAppIcons</string>
            </array>
        </dict>
    </dict>
...

Note the name of the asset catalog goes in there as the only array element and you don’t include the file extension.

You also don’t need to have the CFBundleIconName key (despite the wording of the validation error I was getting). Xcode gets everything it needs from the asset catalog instead.

Step 3: In CMake, copy the asset catalog into the Resources folder

Unlike what @craig.scott suggested, it’s not sufficient to just include the asset catalog folder. You have to include all the folders and files in the structure and you have to preserve the folder structure.

# Asset catalog root
target_sources(MyApp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets")
set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets" PROPERTIES
    MACOSX_PACKAGE_LOCATION Resources
)

# Asset catalog app icon set
list(APPEND app_icon_set "${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets/AppIcon.appiconset")
list(APPEND app_icon_set "${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets/Contents.json")
set_source_files_properties(${app_icon_set} PROPERTIES
    MACOSX_PACKAGE_LOCATION Resources/MyAppIcons.xcassets
)

# Asset catalog icon files
file(GLOB app_icon_files CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets/AppIcon.appiconset/*.png")
list(APPEND app_icon_files "${CMAKE_CURRENT_SOURCE_DIR}/MyAppIcons.xcassets/AppIcon.appiconset/Contents.json")
set_source_files_properties(${app_icon_set} PROPERTIES
    MACOSX_PACKAGE_LOCATION Resources/MyAppIcons.xcassets/AppIcon.appiconset
)

Step 4: Manually set the App Icon field

Run CMake to generate the Xcode project and open that in Xcode.

You can verify the following:

  • In your folder structure you’ll see Root folder > MyApp > Resources > MyAppIcons. Click this and you’ll see the AppIcon icon set.
  • In your folder structure you’ll see Root folder > MyApp > Resources > Info. Click this and you’ll see the contents of your generated Info.plist. You should see Icon files (iOS 5) > Primary icon > Icon files > Item 0: MyAppIcons

Now you have to do a manual step in Xcode that unfortunately CMake can’t do AFAIK:

  • Select the project root folder.
  • In the main panel, select your MyApp target. It’ll have a generic app icon to its left.
  • Select the General tab
  • Under App Icons and Launch Screen, set App Icon to AppIcon. This is what tells Xcode the name of your app icon within the asset catalog you’ve already identified in the Info.plist.

You should now find that if you build and run the app on a device, the app icon is present.

Step 5: Create a release build before you archive (if using CMake < 3.25)

There’s an issue with CMake 3.24 and below that means archives don’t get generated properly. Here’s the workaround:

  • In Xcode, go to Product > Scheme > Edit Scheme…
  • Select MyApp target (top left item of main white panel, even though it doesn’t look selectable)
  • Select Run on the left
  • Change Build Configuration to Release. (I uncheck Debug executable too but I don’t know if this matters.)
  • While you’re there confirm that the left pane now says Run (Release) and Archive (Release)
  • Close the panel
  • Go to Product > Build For > Running. This generates the necessary files both for running and for archive.

Now you can go Product > Archive and, assuming you’re code signing is properly set up, you should be able to Validate app successfully.

Phew! :sweat_smile: