Best way to manage Development, Testing and Production iOS builds with different settings

Problem Statement

Suppose you need to manage three API with different API Keys and some different settings

  • For development or internal testing build - Development distribution outside the iOS App Store
    Host - devapi.project-name.com
    API Key - development_key

  • For client testing build - Enterprise distribution outside the iOS App Store
    Host - stgapi.project-name.com
    API Key - enterprise_key

  • For production build - Distribution in the iOS App Store
    Host - api.project-name.com
    API key - app_store_key


You are able to manage two setting by using DEBUG

#if DEBUG
    #define API_BASE_URL @"http://devapi.project-name.com/api/v1"
    #define API_KEY @"development_key"
#else
    #define API_BASE_URL @"http://stgapi.project-name.com/api/v1"
    #define API_KEY @"enterprise_key"
#endif

First Problem

Enterprise distribution (for client testing) and iOS App Store distribution (production) build, for Enterprise and App Store distribution every time need to change code

  • For Enterprise distribution
#if DEBUG
    //debug setting
#else
    //enterprise setting
    #define API_BASE_URL @"http://stgapi.project-name.com/api/v1"
    #define API_KEY @"enterprise_key"
#endif
  • For App Store distribution
#if DEBUG
    //debug setting
#else
    //app store setting
    #define API_BASE_URL @"http://api.project-name.com/api/v1"
    #define API_KEY @"app_store_key"
#endif

We need a way something like this

#ifdef DEVELOPMENT
    #define API_BASE_URL @"http://devapi.project-name.com/api/v1"
    #define API_KEY @"development_key"
#elif ENTERPRISE
    #define API_BASE_URL @"http://stgapi.project-name.com/api/v1"
    #define API_KEY @"enterprise_key"
#elif APP_STORE
    #define API_BASE_URL @"http://api.project-name.com/api/v1"
    #define API_KEY @"app_store_key"
#endif

Second Problem

Is there any way to create three build with different name without creating different target?

  • ProductName - For App Store
  • ProductName-Dev - For Internal Development build
  • ProductName-Stg - For Client Testing (Enterprise) build

Solution

Create Individual Configurations

In the project (not target) settings, create (duplicate from the originals) the following configurations:

  • Debug_Dev
  • Debug_Staging
  • Debug_Prod
  • Release_Dev
  • Release_Staging
  • Release_Prod

Note that if you use Cocoapods then you will need to set the configurations back to none, delete the contents of the Pods folder in your project (Not the Pods project) and re-run pod install.

Create a scheme for each environment

Instead of just having a MyApp scheme, create the following (duplicate the original):

  • MyApp_Dev (Development)
  • MyApp_Stg (Staging)
  • MyApp (Production)

In each scheme, use the associated Debug_* and Release_* configurations where appropriate.

Here the final look

Add a preprocessor macro to identify environments

Add an additional preprocessor macro to identify what environment you are building against.

In the project build settings, click the + and add a user defined build setting and call it something like MYAPP_ENVIRONMENT. Then, for each different group of environments, add a different preprocessor macro to each one. i.e DEVELOPMENT=1, STAGING=1 and PRODUCTION=1.

Then, in the c preprocessor macros (again on a project level and not the target level) add this new MYAPP_ENVIRONMENT setting using $(MYAPP_ENVIRONMENT).

Finally it's look like this

This way, you can then determine what environment you are building against like so:

#ifdef DEVELOPMENT
    NSString * const MyAppAPIBaseURL = @"https://api-dev.myapp.com/";
#elif STAGING
    NSString * const MyAppAPIBaseURL = @"https://api-staging.myapp.com/";
#elif PRODUCTION
    NSString * const MyAppAPIBaseURL = @"https://api.myapp.com/";
#endif

It's probably a lot to take in.


You can then also create different user defined build settings to do different things, like change the display name of your app.

You could do this by creating a new setting called MYAPP_DISPLAY_NAME for example (same as we create preprocessor macro to identify environments), set the correct name for each configuration and then in your info.plist set the value of the Bundle Display Name to $(MYAPP_DISPLAY_NAME).

Completed Project -

https://github.com/vineetchoudhary/BuildManagement


Discussion

Read Community Guidelines
You've successfully subscribed to Developer Insider
Great! Next, complete checkout for full access to Developer Insider
Welcome back! You've successfully signed in
Success! Your account is fully activated, you now have access to all content.