Developer Blog

Modifying the iOS Settings.bundle Using Build Phases

Most iOS apps today communicate with a server to send and receive data. During development you may have several servers (QA, Staging, Prod) and oftentimes find that you need to distribute copies of your app pointing to each server.

A common approach here is to create a temporary “debug” page where you can configure which server you want your app to use.

This is a good solution but a more elegant one exists. The idea is to create a settings page in the iOS settings app, where you can select between servers or enter your own custom URL. This solution keeps debug code down to a minimum and is less disruptive not requiring an entire debug page created in the app.

Settings.bundle

In order to add an app setting page to the iOS settings app, you must create a Settings.bundle file.

Below is a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<dict>
  <key>PreferenceSpecifiers</key>
  <array>
      <dict>
          <key>Title</key>
          <string>Restart app after making changes</string>
          <key>Type</key>
          <string>PSGroupSpecifier</string>
      </dict>
      <dict>
          <key>DefaultValue</key>
          <false/>
          <key>Key</key>
          <string>use_dev</string>
          <key>Title</key>
          <string>ON-Dev OFF-Staging</string>
          <key>Type</key>
          <string>PSToggleSwitchSpecifier</string>
      </dict>
      <dict>
          <key>AutocapitalizationType</key>
          <string>None</string>
          <key>AutocorrectionType</key>
          <string>No</string>
          <key>DefaultValue</key>
          <string></string>
          <key>IsSecure</key>
          <false/>
          <key>Key</key>
          <string>custom_URL</string>
          <key>KeyboardType</key>
          <string>Alphabet</string>
          <key>Title</key>
          <string>Other (i.e. ab.com)</string>
          <key>Type</key>
          <string>PSTextFieldSpecifier</string>
      </dict>
  </array>
  <key>StringsTable</key>
  <string>Root</string>
</dict>
</plist>

And the resulting settings page:

Alt text

Build Phase Run Script

The problem with the above solution is that you must remember to remove the Settings.bundle file when archiving your app for the store.

Taking our solution to the next level, during an App Store build, the build phases run script can be used to zap this settings page and replace it with something useful. For the purpose of this blog, we will replace the page with the version number of the app.

Below is an example build phase run script that deletes the current settings when building for the App Store and creates new elements for displaying the app version number:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if [ "$CONFIGURATION" == "AppStore" ] ; then

APPVERSION="`/usr/libexec/PlistBuddy -c \"Print :CFBundleVersion\" \"$CODESIGNING_FOLDER_PATH/Info.plist\"`"
SETTINGSBUNDLEPATH="$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist"

/usr/libexec/PlistBuddy -c "Delete :PreferenceSpecifiers" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :StringsTable string 'Root'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers array" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0 dict" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0:Type string 'PSGroupSpecifier'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0:Title string 'Version Information'" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Type string 'PSTitleValueSpecifier'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Title string 'Release:'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Key string 'appVersion'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:DefaultValue string '$APPVERSION'" "$SETTINGSBUNDLEPATH"

fi

And the resulting settings page:

Alt text

Note that as an added benefit, using the Settings.bundle (even if it is just displaying your app version) is a good way to widen the footprint and exposure of your app since it will be listed in the main settings page.

Comments