Swift: How to add Settings to the Apple Watch App?

One of the most asked features of the Cheat-sheets app was to add the possibility to change the font size of the cheats/notes on the users’ Apple Watch. Yesterday this feature was added to the app.

So, how to add settings to the Apple Watch? In general there are two ways to proceed. One option is to add some custom “Settings” button in your iOS app and let user to configure Watch-settings. Maybe this is also the way I’ll go in the future. But for now I decided for the second option to utilize the standard way that Apple suggests, i.e. settings bundle.

How to add Settings-Watch.bundle to your app is best describe at the Apple’s docs. I also found useful this blog posting. Following steps are required:

  1. Add Settings-Watch.bundle file to your iOS target. Yes, to your iOS app and not the WatchKit target 😉
  2. Enable the App Groups capability for your iOS app, WatchKit extension, and Watch app
  3. Important: add the ApplicationGroupContainerIdentifier key to the Root.plist file of your Settings-Watch bundle. Place the key somewhere at the top level of your property list. Set its value to the identifier you specified in the App Groups capability
  4. Define your settings
  5. To localize your settings bundle just duplicate lproj folders and call them like de.lproj or ru.lproj. Use Root.strings files for translations.

So now the settings must be visible in the Watch-App of your iPhone like this:

To access the settings in your Watch app, i.e. some WKInterfaceController just use the code:

let defaults = NSUserDefaults(suiteName: "group.com.example.MyWatchKitApp")
let enabled = defaults?.boolForKey("enabled_preference")

In the Cheat-sheets app the changes of the Settings are immediately seen in the Watch-App. Be aware that your Watch app will not be notified about changes in your NSUserDefaults, because they are changes in another process. That is why this will not work:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadFontSize", name: NSUserDefaultsDidChangeNotification, object: nil)

You have to add KVO observer to every parameter in your NSUserDefaults:

let preferencesUserDefaults = UserDefaults(suiteName: "group.com.example.MyWatchKitApp")
                preferencesUserDefaults?.addObserver(self, forKeyPath: "enabled_preference", options: NSKeyValueObservingOptions.new, context: nil)

To listen to the changes just override the function:

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
     // do your stuff here
    }

And of course do not forget to unregister the observer if you do not need it anymore.