Upcoming and OnDemand Webinars View full list

WatchKit Extensions: Communicating with your Parent Application

Sean Farrell

The release date for the long-awaited Apple Watch has not yet been announced, but the nerd herd here is hard at work learning how to program with WatchKit. We believe that the 4th beta of Xcode 6.2 is a rather stable version of what we should expect for the public release of iOS 8.2 and WatchKit early this year.

With the first beta release of WatchKit in November of last year, developers noticed concurrency issues between WatchKit Extensions and their hosting iOS counterparts, mainly due to a lack of ability to communicate between the two separate processes during runtime. And what if the hosting application was not running at all on the host device? This is a very likely scenario if users were to play around with their Apple Watch while their iPhone was asleep in their pocket. These issues presented serious challenges to providing a seamless user experience.

Previously-available solutions included:

  • duplicating functionalities from your iOS app into your WatchKit Extension
  • creating a Framework for both targets to use (Apple’s recommended solution)
  • creating your own form of messaging between the WatchKit Extension and hosting iOS application, which many developers have tried

With the release of Xcode 6.2 Beta 2, Apple added a method that would allow a WatchKit Extension to communicate back and forth with its host app. The new method, -openParentApplication:reply:, allows the WatchKit app to wake its parent app and send it an NSDictionary.

The host app handles this request by implementing a new method in the app delegate, -application:handleWatchKitExtensionRequest:reply:. Here, you have the option of sending a response NSDictionary back to the WatchKit Extension.

This request-reply mechanism solves the problems we discussed earlier by allowing for simple communication between the WatchKit Extension and the hosting application.

Using -openParentApplication:reply:

Let’s take a look at a simple example of the power and benefits of these new methods. Here, we have an Apple Watch app that allows the user to select one of three words which rhyme with “at”: cat, hat and my coworker, Mat. The selected word will appear as an image in a WKInterfaceImage (the WatchKit equivalent of a UIImageView). You can download this sample project here.

Main WatchKit App

Of course, if we are adding this WatchKit Extension to a fully fledged iOS app that already has image fetching methods, why rewrite those in our WatchKit Extension? What we can do is use our handy new -openParentApplication:reply: method and pass in our desired image title in the NSDictionary. Each of our buttons will pass its title as a string into our method below:

func getDataFromParentApp(image: String) {
	let dictionary = ["Desired Word":image]
	WKInterfaceController.openParentApplication(dictionary) {
		(replyInfo, error) -> Void in
		...
	}

openParentApplication, as with any other communication between the Apple Watch and iPhone, will occur over bluetooth magic, without requiring you to do anything. Over in our AppDelegate of our iOS target, we will need to implement the other side of our method:

func application(application: UIApplication!,
	handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!,
	reply: (([NSObject : AnyObject]!) -> Void)!) {
		getImageForWordThatRhymesWithDat(userInfo, reply)
}

We already have a method in our iOS application called getImageForWordThatRhymesWithDat, which expects an NSDictionary with the key “Desired Word” and a value containing the name of the image we desire. The method returns an NSDictionary with the key “Returned NSData” and the NSData of our image.

We will leave out the details of our getImageForWordThatRhymesWithDat method and let you imagine it is a method you have already built in one of your current iOS applications. Maybe you want to pass back a different set of data based on what your application already implements. Just make sure the data can be held in NSDictionary and transfers correctly through our two methods.

Now that our NSData is getting sent back to the WatchKit Extension, let’s look back at the completion block of our earlier openParentApplication method.

(replyInfo, error) -> Void in
	switch (replyInfo?["Returned NSData"] as? NSData, error) {
		case let (data, nil) where data != nil:
                	let image = UIImage(data: data!)
                	self.imageView.setImage(image)
		case let (_, .Some(error)):
			println("got an error: (error)") // take corrective action here
		default:
			println("no error but didn't get data either...") // unexpected situation
	}

We have now received our image NSData (or possibly an error), and we can act accordingly and set our WKInterfaceImage.

Dog WatchKit App

Our new openParentApplication method solves several problems we discussed earlier:

  • -openParentApplication:reply: allows us to briefly access our parent app when it is asleep.
  • -handleWatchKitExtensionRequest:userInfo:reply: can send data from our parent application back to our WatchKit Extension, lessening the need for code duplication or Frameworks.
  • We are adhering to Apple’s desire for the WatchKit Extension to represent another view for your iOS application, leaving much of the model and controller logic in the main iOS application.

Thanks for the new method, Apple! We are glad that they realized the issue early on and listened to developer demand. We hope this explanation helps with your early WatchKit wisdom.

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project