Custom iOS Settings per Configuration
Tags: ios
Published: 2017-08-05 16:16:42

---
title: Custom iOS Settings per Configuration
published: true
description: How to have different settings bundle per configuration to have ability to configure app with dev-only values like a different backend server.
tags: ios
---

# Custom iOS Settings per Configuration

Sooner or later, many companies face a need to provide extra information or customisation for an app. For me it was usually the ability to target non-production servers and choose between dev, test and prod server environments.

There are multiple ways to achieve it, and the easiest is probably providing custom Settings bundle in iOS system Settings section for your app.

## Adding a Settings Bundle

Adding a settings bundle is as simple as adding a new class.

![Adding a bundle to Xcode project][iosdev_settings_add]

In the [example project](https://github.com/coverback/CustomSettingsBundle) I’ve added two bundles, `ProdSettings` and `DevSettings`.
After you’ve added them, remove the bundles from the `Copy Bundle Resources` building phase, as you’ll be copying them manually in the next step.

## Overriding the Bundle Based on the Configuration

In the build phases for your target, add a new build step `New Run Script Phase` and place it after `Copy Bundle Resources` one.
![Adding build phase to Xcode building][iosdev_settings_script]

The script to copy the correct bundle would look something like this: 

```bash
SRC_DIR="${PROJECT_DIR}/CustomSettingsBundle"
if [ "${CONFIGURATION}" != "Release" ]; then
    cp -rf "${SRC_DIR}/DevSettings.bundle" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle"
else
    cp -rf "${SRC_DIR}/ProdSettings.bundle" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle"
fi
```

## Usage

Just like with normal settings, accessing values happens through `UserDefaults`. 

```swift
UserDefaults.standard.bool(forKey: "dev_preference_enabled")
```

Note that removing a setting from the bundle won’t clear the corresponding key in `UserDefaults`, and until the setting is updated at least once, it will be `nil` regardless of the default value in the `plist` of the settings bundle.

## Gotchas

Settings in the end product folder have to be named `Settings.bundle`. Maybe you could change this requirement somewhere, but because of that example script also renames the folder itself.

iOS Settings are cached, so switching between configurations require project cleaning and may require an app reinstall to force the change of the settings contents. My suggestion would be to have beta/dev builds with separate bundle ID so you can have multiple versions of the app installed simultaneously without having to reinstall to test configurations.

Another issue is with the iOS Settings app itself. Sometimes all  the apps would disappear from it, so a restart of the Settings app is often required if you switch and especially if you install an app while having Settings app open.

## Alternatives?

Providing custom Settings bundle is very easy, but not very flexible. The next best thing is doing it via a special screen hidden under Debug/Beta-only button on the app’s landing screen.

The biggest gain is not having to leave the app to switch environment and not having to remember to kill the app if your settings are only read at launch-time. With a custom code you can make “Save” to perform data saving and then `exit(0)`.

[iosdev_settings_add]: https://thepracticaldev.s3.amazonaws.com/i/49qsixu0tj4nicfxcwhf.png
[iosdev_settings_script]: https://thepracticaldev.s3.amazonaws.com/i/9gc48o4qtzpu0famk7gw.png