Skip to main content

Building iOS apps using xcodebuild with multiple configurations

·4 mins

(UPDATE: 29 Jan 2018. Tested on 9.2)

Xcode handles app signing automatically. This is excellent for single app distribution via TestFlight! You might need more granular or manual control of your app builds; different apps for different environments; apps provisioned for specific test users. You’re probably more suited to manual builds. Enter xcodebuild and xconfig files!

If you’re looking for a quick way to get up and running with multi-config command-line builds, keeping you close to the xCode toolset, keep on reading! xcConfig files are great for this purpose and can be used to include provisioning information too. Its also an easy way to create your own CI shell script implementations.

For something more extensive – check out Fastlane and Buildkite. Fastlane is excellent for some serious CI with vast iOS tools. Buildkite is a very flexible build agent. I’m impressed with its reliability – up and running in minutes too. Their support was impressive too!

you’re going to need… #

  • Your Apple Developer Team ID
  • Your App ID setup on the Apple Developer website.
  • Signing Certificates and provisioning profiles for each environment,  synced to your xCode 8 environment

start with the demo app #

SigningTest is demo app setup for multi-config usage. Source code is on Github. The project has been setup for debug, staging and release configurations.

  • Debug – configuration for building to developer devices
  • Staging – configuration for building to a staging environment. Possibly a limited set of users Staging builds aimed at a limited set of users (by device)
  • Release – release builds destined for the app store

You’ll need to make some minor modifications. Make it work with your Team, App ID and provisioning profile configs. Read through setup is below, followed by some explanations.

Setup #

  • checkout SigningTestApp project from Github
  • Open and search project for ‘DEVELOPMENT_TEAM’. It’ll be set to ‘ YOURTEAMHERE’. Replace with your Apple Team ID
    • from your project root in Terminal/Finder
      • modify exportOptions/adhoc.plist
        • “teamID”:”YOURTEAMHERE”. Replace with your Apple Team ID
        • “provisioningProfiles”. Map your bundle ID to your provisioning profile name. Replace BUNDLE__ID, PROVISIONING__PROFILE_NAME with your adhoc  build information
      • modify exportOptions/store.plist
        • “teamID”:”YOURTEAMHERE”. Replace with your Apple Team ID
        • “provisioningProfiles”. Map your bundle ID to your provisioning profile name. Replace BUNDLE__ID, PROVISIONING__PROFILE_NAME with your app store  build information
  • I’ve configured three xCode configurations in the Config folder. Each uses its own .xcConfig file Modify, or delete them to suit your needs.
    • Development – for developers on the project, with a profile for specific devices (developer devices)
    • Staging – an adhoc profile, with a profile for specific devices (testing devices)
    • Release – the app store distribution profile for the app (app store provisioning)
  • Edit the three xcConfig files, and replace them with your specific configs. Here are mine. Yours should be different.
Debug.xcconfig #
PRODUCT_NAME = SigningTestDebug
PRODUCT_BUNDLE_IDENTIFIER = org.sagorin.signingtest.debug.SigningTest
PROVISIONING_PROFILE_SPECIFIER = SigningTest Debug Profile
Release.xcconfig #
PRODUCT_NAME = SigningTest
PRODUCT_BUNDLE_IDENTIFIER = org.sagorin.signingtest.SigningTest
PROVISIONING_PROFILE_SPECIFIER = SigningTest App Store Distribution
Staging.xconfig #
PRODUCT_NAME = SigningTestStaging
PRODUCT_BUNDLE_IDENTIFIER = org.sagorin.signingtest.staging.SigningTest
PROVISIONING_PROFILE_SPECIFIER = SigningTest Staging Distribution
  • Close your project, and re-open it. This step was necessary to pick up the values for the provisioning profiles per configuration. Strangely, I only needed to do this once?
  • Check the changes have been applied:
    • Project..Target..General. Signing (Debug,Release, Staging – they should all pickup the values from your xcconfig files)
  •  Now can run the app in the Simulator – make sure it launches.
  • From a Terminal window, at your project root, run one of the following commands. It’ll build an IPA file – per configuration:
./build.sh Release
 ./build.sh Staging
 ./build.sh Debug

Thats it. You’ll have a shiny new .ipa  in ./build folder

explain please! #

xc-configs #

Values in xcConfig files are automatically used per build configuration.  In the sample app, check out Project..Info to see how they’re configured. For the sample app, I used a single App ID with a wildcard on the ID (org.sagorin.signingtest.*). I made three provisioning profiles. For a real app, you’ll probably use a unique Bundle ID. xcConfigs can give you the flexibility to use different App IDs per configuration. This allows for broader distribution of apps from one project.

build script #

The build script is a very basic shell script. Using xocdebuild, it’ll create an archive, and then the .IPA. When creating the .IPA, we specify the IPA options using ‘exportOptions’. Information like bitcode, dsyms upload, team information. All are specified in exportOptions. Run ‘xcodebuild –help’ for more all options available for exportOptions

In the demo app, the build script can build for Debug, Staging and Release. Release builds use the store.plist – all the others use adhoc.plist.

a bonus: cocoapods! #

The demo project has a branch for cocoapods, setup with a workspace with the same configs. I used a demo pod entry for Google Analytics.

  • Open the workspace file, not the project file, and follow the same setup instructions above.

Any questions or problems with the above example? please email me!