Earlier this year I put together a tutorial for WatchKit development. Check it out and my youtube channel here:
Have you ever wondered how to communicate from your WatchKit app to its containing iOS app?
openParentApplication is a method on WKInterfaceController. It allows you to pass in an object that contains the information you want to pass along to the WatchKit app’s containing iOS app.
Here is a simple example:
Here I am sending a dictionary with a key of ‘buttonClicked’ and value of type String that represents which button in my UI was clicked. If you look at the method signature on openParentApplication, you’ll see that it accepts an NSObject of AnyObject:
That’s simple enough. What about receiving this message on the containing iOS app end?
Add handleWatchKitExtensionRequest to your application’s AppDelegate.
handleWatchKitExtensionRequest allows you to receive the object you had sent from your WatchKit app. In this example, since I had sent a dictionary from the WatchKit app, I get a dictionary on the iOS containing app’s side. I then look inside the dictionary for the existence of the key I had set on the WatchKit side, checking for nil. If the key exists in the dictionary, I print it out.
What about that reply parameter?
openParentApplication allows you to pass a closure via the reply parameter. This allows you to send a message from the containing iOS app to the WatchKit app. I will modify my example to demonstrate this. Here, instead of passing in nil for reply, I pass in a closure:
The closure for the reply parameter expects a dictionary and an NSError to be passed to it. If I run this code, what happens? The closure is executed, but we get an error:
Fortunately, the error is very helpful: ‘The UIApplicationDelegate in the iPhone App never called reply()’. So let me fix that. For simplicity’s sake, let’s say that I wanted the iOS app to communicate back to the WatchKit app a count of the number of times a particular button had been clicked. I’ll simply invoke the reply closure, passing along a dictionary of the desired information:
Back on the WatchKit side, in the else block, the dictionary that we received from the containing iOS app gets printed out:
When I run the WatchKit app, I now get the dictionary printed out to the debugger:
Something you should be aware of is that the containing iOS app launches in the background. This is fine except that the normal app lifecycle is triggered and executes. For example, your app’s viewWillAppear method will be called. The way I got around that in my app is by adding the following to the containing iOS app’s AppDelegate didFinishLaunchingWithOptions method:
openParentApplication and handleWatchKitExtensionRequest are a powerful combination. Use them when you want to send information between your WatchKit extension and its containing iOS app. Be aware that the iOS app’s lifecycle is triggered and executes, even with the app running in the background.
Do you have any feedback? What has your experience been with these two methods? Let me know in the comments section below.