All Articles

Watchkit + MagicalRecord + Core Data

Intro

Apple Watch is all the hype right now. With its release next week, app developers are hastily assembling their WatchKit app (myself included). One core concept that is paramount in building a great WatchKit app is the idea of sharing persistent data between the actual iOS app and WatchKit app. Specifically how do I get a shared storage unit that can be shared across both my iOS and WatchKit app?

The model here that I demonstrate is the iOS app can Read and Write to persistent storage. The WatchKit app can only Read to persistent storage. I also will be showing a technique specific to MagicalRecord which is just a higher-level wrapper around CoreData.

Prerequisites

As the Apple Watch is ancillary to your iOS app, I am assuming you already have your iOS app setup already integrated with MagicalRecord presumably through CocoaPods.

High Level

The higher level overview is as followed:

  1. Create Watch App Target
  2. Add a shared App Group container
  3. Update location of the Persistent Data Store to point to the App Group container
  4. Create Framework that wraps all Core Data access code as to keep your code DRY
Breaking it down

Step 1

Create Watch App Target

  1. File -> New Target -> Apple Watch -> WatchKit App
  2. Setup CocoaPods with MagicalRecord for the WatchKit extension

    target '(Target Name)' do
    pod 'MagicalRecord'
    end

    In my case, my (Target Name) is ‘WatchkitTutorial WatchKit Extension’

  3. pod install

Step 2

Add a shared App Group container

The purpose of this step is to have entitlements to allow shared authorized access to a container for both the iOS and WatchKit app. This will authorize the use of a shared Database.

  1. Go to Certificates, Identifiers, & Profiles under developer.apple.com
  2. Under iOS press, any one of those options -> On the left side bar go to App Groups (Identifiers)
  3. Add a new App Group, I called mine ‘group.com.watchkittutorial.watch’ Remember this for later.
  4. Go back to Xcode and under the Project Directory, go to your iOS app target go to capabilities. Turn On App Groups and select the App Group you created on Step 3.
  5. Do the same as Step 4, but for your WatchKit Target this time.

At this point, this tells your iOS and WatchKit app that they are allowed to communicate with each other.

Step 3

Update location of the Persistent Data Store to point to the App Group container

Now that both apps have access to the shared container, let’s make sure that MagicalRecord points to this new shared location.

In your iOS app, in your AppDelegate didFinishLaunchingWithOptions, add in this code In your WatchKit app, in your first InterfaceController willActivate, add in this code

    NSFileManager *fm = [NSFileManager defaultManager];
    NSString *appGroupName = @"group.com.watchkittutorial.watch";
    NSURL *groupContainerURL = [fm containerURLForSecurityApplicationGroupIdentifier:appGroupName];
    NSString* dbPath = [groupContainerURL path];
    
    dbPath = [dbPath stringByAppendingPathComponent:@"ModelWatchKit.sqlite"];
    NSURL* dbURL = [NSURL fileURLWithPath:dbPath];
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(id)dbURL];

Step 4

Create Framework that wraps all Core Data access code as to keep your code DRY I actually will not go into this. I added this since I saw many blog posts go into depth with this step as their tutorial was WatchKit + Core Data, not WatchKit + MagicalRecord + Core Data. I have found it unnecessary since the idea with this step is that Core Data functionality out of the box is quite low-level so we would want to abstract these low-level tools into one that is higher level while also wrapping our custom data model into something higher-level. With this logic of just using Core Data, we can, therefore, create a Core Data Framework that is specific to our app and can share the same higher-level persistent operations in one easy to use Framework. With MagicalRecord, the low-level things about Core Data have already been wrapped with as MagicalRecord does sit on top of Core Data. In the context of my app, I did not have to abstract MagicalRecord a level up to wrap around my data models therefore I do not need a Framework (your use-case may vary!)

Step 5

With Step 4 explain, you are actually all set! If you’ve done it right, both apps will have access to a common database.

I’m @steventsooo on Twitter. I would love to hear what you think!

Published 16 Apr 2015