Setup developer tools in iOS projects for internal testing (Part 1)


B y nowadays almost every mobile application’s developing and maintenance process coming with multiple backend environments. i.e QA process executes firstly on the development environment and then on “production” (actually, there can be some intermediate environments instances). In project it’s looks something like this:

It’s pretty simple to set up a specific environment that depends on project build configuration. And all seems to be ok when QA’s asks you to make a build with the different environment. What you need — it’s just to ̶h̶a̶r̶d̶c̶o̶d̶e̶ setup specific build configuration and press Archive button. But when there are need to test some mysterious bug, or you have maintaining so many applications — this is so time consuming-routine work.

So, in that case, we need some handy switching tool directly in binary on the device. The first thing that appears in mind — add something like debug options field with controls somewhere in user profile or settings inside the application. But don’t hurry up. In iOS, the Cocoa framework provides the low-level mechanism for storing the preference data (more about Settings bundle you can read here). Setting for and getting value from Settings.bundle performs via NSUserDefault and KVO

In the first part of this article, I’ll describe opt-in feature that presents in current applications on our product.

NB: It applies only to follow project configuration.
* Debug(obviously for developing process) 
* Ad-Hoc(distributing builds for internal testing)

First of all, let’s provide some entry point for this stuff.

  • So, basically the env. variable sets up like a string constant;
  • a user must have the ability to change it;
  • an application must handle these changes and react properly

Let’s do it.

  1. Xcode has a template for this, simply click on “Add files” and in search field make a query “Settings” — you must see something like this:
Choosing a template Settings Bundle

2. Save it somewhere (i.e in Resources folder) in your project.

3. If you did all right, then you can open the Root.plist file (this is the main file in our feature viewpoint).

Settings.bundle tree structure

The next step is to edit .plist fields properly according to our specification.

Root.plist fileds

1. Add a name for a group (i.e “Debug preferences”)

2. Press Pluss(+) sign on Preference Items filed and add Multivalue. Then you need to set key/value pairs such as Identifier (used to communicate through given name in code), Title, DefaultValue (i.e Development), Type (Multi value by default), and “Titles” / “Values” constants for those(see the documentation for more information). When you finish, plist should look like this:

Complete Root.plist in view mode

As it’s .plist file — you can do all of this process just in XML:

3. When we done with configuring Root.plist — some interface needs to be written for handle changes and adopt it in application.

It’s pretty simple class above and we pass an enableSwitching to the initializer. This step is important, because the goal of this — is to bring ability of changing environments only for Internal Builds. Later we can call designated initializer with specific Bool value depending of the project configuration and user-defined swift flags. like DEBUG, ADHOC (we can use them in macros definition)

The main part of this functionality is apiEnvironment getter. It’s encapsulates call to the NSUserDefaults (where target values actually stores), and return the user-defined environment instance.

Settings bundle in action

One more thing…

An underwater stone appears when I actually start thinking about an ability to hide this debug preferences for Release and Testflight builds. On this moment we can simply prevent initializing of SettingsBundleHelper instance by checking the current project configuration and include swift flag definitions. It looks like this:

But UI in Settings is still present and it isn’t very good to include it in Release builds. So we need to exclude the Root.plist file when archiving, depending on configuration. Unfortunately there are no such a flexible way to do this on build time. But as it’s a .plist, we can left there own version of file instead of defined, using PlistBuddy.

PlistBuddy is a tool provided by Apple to perform operations on a plist file using bash commands. We can add, edit and delete any values in a plist. You can find it at: /usr/libexec/PlistBuddy.

So we need to include a custom script in build phases to do this:

And add it to Build Phases in app target:

In the script above we substitute a debug tools and just printed the version information of the app. Actually with Plist Buddy you can easily edit your’s Root.plist or any other .plist on the build phase.


Assuming the simplicity of use, we’ve created a pretty handy mechanism to check “on fly” the application behaviour on different API environments. But it isn’t the end, because as we can think more wider and expand this functionality on some other tools. More about toggling analytics in mobile and handling custom ngrok urls in Part 2.