<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Romans Karpelcevs</title>
    <description>The latest articles on Forem by Romans Karpelcevs (@coverback).</description>
    <link>https://forem.com/coverback</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F24734%2F52674cc4-b4bf-46d6-9b69-b4291ce351b8.jpeg</url>
      <title>Forem: Romans Karpelcevs</title>
      <link>https://forem.com/coverback</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/coverback"/>
    <language>en</language>
    <item>
      <title>Custom iOS Settings per Configuration</title>
      <dc:creator>Romans Karpelcevs</dc:creator>
      <pubDate>Sat, 05 Aug 2017 16:16:42 +0000</pubDate>
      <link>https://forem.com/coverback/custom-ios-settings-per-configuration</link>
      <guid>https://forem.com/coverback/custom-ios-settings-per-configuration</guid>
      <description>&lt;h1&gt;
  
  
  Custom iOS Settings per Configuration
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Adding a Settings Bundle
&lt;/h2&gt;

&lt;p&gt;Adding a settings bundle is as simple as adding a new class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rlPTviJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/49qsixu0tj4nicfxcwhf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rlPTviJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/49qsixu0tj4nicfxcwhf.png" alt="Adding a bundle to Xcode project" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/coverback/CustomSettingsBundle"&gt;example project&lt;/a&gt; I’ve added two bundles, &lt;code&gt;ProdSettings&lt;/code&gt; and &lt;code&gt;DevSettings&lt;/code&gt;.&lt;br&gt;
After you’ve added them, remove the bundles from the &lt;code&gt;Copy Bundle Resources&lt;/code&gt; building phase, as you’ll be copying them manually in the next step.&lt;/p&gt;
&lt;h2&gt;
  
  
  Overriding the Bundle Based on the Configuration
&lt;/h2&gt;

&lt;p&gt;In the build phases for your target, add a new build step &lt;code&gt;New Run Script Phase&lt;/code&gt; and place it after &lt;code&gt;Copy Bundle Resources&lt;/code&gt; one.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hxWEo5I6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/9gc48o4qtzpu0famk7gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hxWEo5I6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/9gc48o4qtzpu0famk7gw.png" alt="Adding build phase to Xcode building" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The script to copy the correct bundle would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SRC_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/CustomSettingsBundle"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONFIGURATION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"Release"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SRC_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/DevSettings.bundle"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILT_PRODUCTS_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PRODUCT_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.app/Settings.bundle"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SRC_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/ProdSettings.bundle"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILT_PRODUCTS_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PRODUCT_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.app/Settings.bundle"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Just like with normal settings, accessing values happens through &lt;code&gt;UserDefaults&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;UserDefaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;standard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"dev_preference_enabled"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;p&gt;Settings in the end product folder have to be named &lt;code&gt;Settings.bundle&lt;/code&gt;. Maybe you could change this requirement somewhere, but because of that example script also renames the folder itself.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;exit(0)&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
    </item>
  </channel>
</rss>
