Project Configurations for iOS

Hero image for Project Configurations for iOS

This document presents in details the set of configurations used in the iOS projects developed at Nimble. Included in this document:

  • Terminologies and topics related to project configurations.
  • Basic targets, schemes, build settings options, etc. for building a project.

Targets

A target specifies a product to build, such as an iOS, watchOS, or macOS app.

When creating a project from a template, a default target will be added automatically for the main application. If Unit and UI tests options are selected when initializing the project, Xcode will include specific targets for the main application and the test applications.

There are 3 targets in a project:

  • {ProjectName}
  • {ProjectName}UnitTests
  • {ProjectName}UITests

Schemes

A scheme is a collection of settings that specifies the targets to build for a project, the build configuration to use, and the executable environment to use when the product is launched.

The 4 main schemes in a project:

  • {ProjectName}
  • {ProjectName} Staging
  • {ProjectName} SIT (optional)
  • {ProjectName} UAT

The SIT scheme is not covered hereafter as it is optional.

SIT and UAT

SIT and UAT are two different testing levels of application testing.

  • SIT (System Integration Testing) is responsible for testing the interfaces between the components and interactions to various parts of the systems like hardware, software (operating system and file system), and interfaces among systems.
  • UAT (User Acceptance Testing) is a validation testing performed from the end-user where user requirements and business-related processes are checked to find whether the system can be accepted or not.

The differences between SIT and UAT will be described in the following comparison chart:

  SIT UAT
Focus on Interface between the modules Requirement with the user’s point of view
Performed by Developers and testers Customers and end-users
General issue Data flow, control flow, etc. Functionality issues or non-working features according to the requirements

Configurations and Build Configurations in Schemes

It is possible to build a scheme with different Build Configurations. Initially, there are 2 basic configurations for a project generated automatically by Xcode, which are:

  • Debug
  • Release

However, these basic configurations are not enough for our development process. Since our team always wants to ensure the application is working in a designated manner, additional levels of testing are required before the application is ready to be used.

The recommended set of configurations to have is:

  • Dev Staging
  • Staging
  • Dev UAT
  • UAT
  • Dev Production
  • Production

Rename the existing configurations to more recognizable ones to avoid misunderstanding between the configurations and the compilation conditions’ environments.

  • Change Debug Configuration to Dev Configuration.
  • Change Release Configuration to Production Configuration.

Active Compilation Conditions

Having distinct flags for each configuration is the preferred solution.

Xcode provides a build setting named Active Compilation Conditions, which supports passing conditional compilation flags to the Swift compiler.

In an iOS project, there usually are four custom conditional compilation flags, which are: DEBUG, UAT, Staging, Production. The following table will describe how the developers differentiate a configuration from the others.

  DEBUG UAT Staging Production
Dev UAT ✔︎ ✔︎    
UAT   ✔︎    
Dev Staging ✔︎   ✔︎  
Staging     ✔︎  
Dev Production ✔︎     ✔︎
Production       ✔︎

The huge advantage when using custom flags is customizable specific features based on a particular environment.

Example: Specify a value based on the environment:

enum Environment {
    static func based<T>(staging: T, uat: T, production: T) -> T {
        #if PRODUCTION
        return production
        #elseif UAT
        return uat
        #else
        return staging
        #endif
    }
    ...
}

During the development process, all functionalities and frameworks are available in the application. However, there can be situations when some features must be toggled on for a particular environment without creating separate modules for the application. In these cases, taking advantage of Active Compilation Conditions by declaring a condition to include or exclude code is the recommended solution.

#if DEBUG
    // Code the app includes in DEBUG environments
#else
    // Code the app includes when it is not build with DEBUG environments
#endif

Example: By using these flags, the developers can add some utilities which help us debugging and testing our application, such as Settings Bundle for Dev Configurations only (such as Dev UAT, Dev Staging, Dev Production).

#if DEBUG
    setUpSettingsBundle()
#endif

xcconfig file

A Configuration Settings File (*.xcconfig), also known as a build configuration file, is a plain text file that defines and overrides the build settings for a particular build configuration of a project or target. This type of file can be edited outside of Xcode and integrates well with source control systems.

Because of different settings for each environment (such as bundle identifiers, endpoints, etc.), the developers also define them in different *.xcconfig files.

Settings Bundle

To support multiple levels of testing, the Settings Bundle is usually integrated along with the dev configurations. The Settings Bundle facilitates the testing process, by creating a shortcut to change environment values, without using any third-party API or server.

Settings Bundle works well when developing:

  • Feature toggle
  • A/B Testing
  • Change API endpoints for testing the application with multiple servers
  • Define a list of prefilled credentials and a toggle for prefilling

The Settings Bundle is only enabled on Dev environments. It is optional for Beta environments.

Feature toggle

Feature toggle (as known as feature flag, feature switch, feature flipper, etc.) is a technique that attempts to provide an alternative to maintaining multiple branches in source code. Feature toggle is used to enable or disable the feature during runtime. In this way, feature toggle can be used to deliver specific features to targeted subsets of users.

A/B Testing

A/B Testing (also known as bucket testing or split-run testing) is a user experience research methodology. It consists of a randomized experiment with two variants, A and B.

A/B Testing is a statistical way to compare two versions of a single variable, typically by testing a subject’s response to variant A against variant B, and determining which of the two variants is more effective.

dSYM file

Basically, the dSYM file (Debug Symbol file) is used to de-obfuscate stack traces from crashes happening on the production app. The dSYM files store the debug symbols for the application. Then services (like Crashlytics) use the dSYM files to replace the symbols in the crash reports with the originating locations in the source code. Hence, the crash reports will be more readable and understandable.

Go to Build Setting → Debug Information Format, the debug symbols with a dSYM file (DWARF with dSYM file) is enabled for the release build by default.

A benefit of using the dSYM is reducing the binary size when building an application. Read more about it in the technical note TN2151.

Only include the dSYM file for Beta and Production only.

  Included dSYM file
Dev UAT  
UAT ✔︎
Dev Staging  
Staging ✔︎
Dev Production  
Production ✔︎

Enable Bitcode

Bitcode is a technology that enables recompiling applications to reduce their size. The recompilation happens when the application is uploaded to the App Store Connect or exported for Ad Hoc, Development, or Enterprise distribution.

Enable build with bitcode for Production only.

  Enable Bitcode
Dev UAT  
UAT  
Dev Staging  
Staging  
Dev Production  
Production ✔︎