Utilizing Schemes and .xcconfig Information to Manage Construct Deliveries in iOS | by Federico Jordán | Jul, 2022


Find out how to outline completely different configurations for our mission

Photograph by Pawel Czerwinski on Unsplash

There are numerous instances that we have to manage our cellular deliveries. This implies, the construct that we use to publish our app in App Retailer, or the construct that we use day-after-day to construct our app domestically, or to distribute internally in our firm are usually not the identical.

Right here we’ll see a technique to manage a bit higher our app deliveries and begin organizing it in inner configurations that make sense in our on a regular basis work.

From Apple paperwork:

Whenever you construct, run, take a look at, profile, or archive a part of your mission, Xcode makes use of the chosen construct scheme to find out what to do. A construct scheme comprises a listing of targets to construct, and any configuration and atmosphere particulars that have an effect on the chosen motion. For instance, if you construct and run an app, the scheme tells Xcode what launch arguments to cross to the app. Xcode offers default schemes for many targets, and you may customise these schemes or create new ones as wanted.

A construct scheme is principally the configuration which relates a goal and any configuration that we might have for that focus on. This consists of atmosphere variables, configuration information, or something that may make the construct customizable.

For instance, we will have the three following schemes:

  • A manufacturing scheme, the one which our customers can obtain at App Retailer
  • A staging scheme, or inner testing one. Additionally could be referred to as Beta
  • A growth scheme, which is used domestically by engineers

This separation of considerations when it comes to builds configuration may also help us to customise the expertise of our app. With such kinds of schemes, we will for instance:

  • Change app icon
  • Use a distinct base URL for our inner API
  • Configure third occasion SDK of their respective environments
  • Add inner growth instruments that may assist QA or Devs groups
  • Keep away from sending data to 3rd events, for instance, we wouldn’t have to ship crashes data to Firebase if we’re compiling the app in native. That might add not actual information to our crashes dashboard.
Instance of Chrome icon with Beta configuration

There may be anoter vital element in our construct system construction, and it’s the Goal. A goal is principally the app that we’re constructing, the product that we goal to construct. Which suggests, all of the supply code that’s wanted to be compiled and at last create the binary. A goal makes use of a scheme to construct a product. We are able to summarize the variations as the next:

A Goal specifies a product to construct and comprises the directions for constructing the product from a set of information in a mission or workspace.

An Xcode scheme defines a group of targets to construct, a configuration to make use of when constructing, and a group of assessments to execute.

As we will use targets to distinguish configuration, that’s not the aim of them. We’ll find yourself making extra sophisticated the construct system and the developer expertise utilizing the mission. A goal builds a product, and a scheme comprises the configuration of construct it.

A key central piece of utilizing schemes is to make use of Xcode Configuration information. These are those with .xcconfig extension.

Mainly we will outline customized values for our desired construct configuration, that we will use later to construct our goal. An instance:

We are able to create many .xcconfig information, and reference inside them one another, to keep away from repeating widespread values between configurations. The next part will clarify this idea higher.

For our instance mission, we’ll have the next:

  • 1 goal referred to as schemes-test
  • 2 schemes referred to as STDevelopment and STProduction
  • 3 .xcconfig information: Widespread.xcconfig, Improvement.xcconfig and Manufacturing.xcconfig

Because the goal is already created when now we have a brand new mission, we’ll proceed to create the schemes. We’ll faucet within the “Handle Schemes…” possibility within the prime menu subsequent to the mission title:

Then, within the Schemes listing view, we’ll faucet on the + button to create a brand new scheme

We’ll create a brand new scheme with the title STDevelopment :

The identical for STProduction

At this level we must always have the next schemes in our listing:

It’s protected to delete the autogenerated schemes-test scheme, since we gained’t use it.

Now, we’ll proceed to create the .xcconfig information. We’ll have to create a BuildConfigurations folder in our mission root.

Then, we’ll create a brand new file with the kind of Configuration Settings File

We’ll name this file Widespread . Then we do the identical steps for brand new information Improvement and Manufacturing . At this level, we must always have these information in our mission:

In Widespread file we’ll enter the next code

In Improvement we’ll enter the next:

And the following strains for Manufacturing:

We outline the next values in our .xcconfig information:

  • PRODUCT_BUNDLE_IDENTIFIER: The bundle identifier of our scheme
  • MARKETING_VERSION: The model quantity for the construct
  • CURRENT_PROJECT_VERSION: The construct quantity
  • BUNDLE_DISPLAY_NAME: The seen title of the app at display

As you may think about, with the #embody key phrase we will embody information. In our case, the values for MARKETING_VERSION and CURRENT_PROJECT_VERSION ought to stay the identical between configurations. However the worth for PRODUCT_BUNDLE_IDENTIFIER is completely different, since we need to have completely different apps for each environments. Similar for BUNDLE_DISPLAY_NAME , which is the seen title of the app

Now the following step is to affiliate these information with the configurations. To do this, we go to the mission settings:

Right here we’ll substitute the Debug and Launch names by Improvement and Manufacturing, simply to match our information names. Additionally we add the corresponding xcconfig information to every configuration:

To have the ability to use these values, we have to go to our Data.plist file, the place we are going to add the next properties, with every matching variable:

  • Bundle identifier with PRODUCT_BUNDLE_IDENTIFIER
  • Bundle model string (brief) with MARKETING_VERSION
  • Bundle model with CURRENT_PROJECT_VERSION
  • Bundle show title with BUNDLE_DISPLAY_NAME

So, we’ll finish with one thing like this:

The identical could be accomplished if we faucet on our goal settings and set the $(…) for every variable of their respective area:

As a final step, we have to hyperlink every scheme with every configuration, so we faucet on Edit Scheme on the prime bar:

We’ll hyperlink every scheme with the associated configuration:

And that’s it! If we run our schemes within the simulator, we’ll see that now we have two completely different apps:

We are able to embody code relating to the scheme in our binary if we would like. For this specific case, we will use the next for Improvement.xcconfig :


And this different one for Manufacturing.xcconfig :


So, in our code we will have the next:

That is very helpful to current hidden menus, or developer/QA utilities to assist debugging.

It’s vital to make the identical numbers adjustments for the take a look at goal, so each important and take a look at goal have the identical model and construct numbers. Similar case for App Extensions. We have to maintain the identical Model and Construct quantity between important goal and App Extensions, in any other case Apple will warn us after we add the construct into App Retailer Join. The message will probably be just like the following one (will probably be acquired by electronic mail additionally)

We are able to add API keys/tokens in .xcconfig information, so then we will outline them in plist information and entry them like this:

let bundleId = Bundle.important.infoDictionary?["APIKey"] as? String

Nonetheless, this isn’t a safe answer. We must always goal to get such delicate information in one other method, as a result of it’s not safe to have them commited in our git repository. If we use a CI to construct and distribute our app, many CI suppliers have the choice to set Secrets and techniques (Bitrise, for example) after which inject these secrets and techniques within the mission with an answer like cocoapods-keys. I’ll speak about do it in a subsequent submit.

We noticed outline completely different configurations for our mission. It’s actually helpful to be organized in such a way that we will use a construct for native growth and one other for manufacturing. That functionality will allow us so as to add correct testing instruments, outline third events environments higher, or simply manage our code in a extra environment friendly method.

You possibly can have a look at the entire supply right here.

Thanks for studying!



Leave a Comment