WatchKit App and Parent iOS App Communication

From Techotopia
Revision as of 20:14, 27 October 2016 by Neil (Talk | contribs) (Text replacement - "<table border="0" cellspacing="0"> " to "<table border="0" cellspacing="0" width="100%">")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
A WatchKit Page-based Navigation TutorialA WatchKit openParentApplication Example Project


Purchase the fully updated watchOS 2/Swift 2 edition of this book in eBook ($12.99) or Print ($27.99) format
watchOS 2 App Development Essentials Print and eBook (ePub/PDF/Kindle) editions contain 35 chapters.

Buy Print


Up until this point, most of the areas covered in this book have related primarily to the interaction between the WatchKit app and the WatchKit extension. There is, of course, a third element that needs to be taken into consideration in the form of the parent iOS app with which the WatchKit app is bundled. As has been demonstrated in the preceding chapters, much can be achieved within the WatchKit app extension. There are, however, certain tasks that can only be performed in the iOS application. In recognition of this fact, the WatchKit framework provides a mechanism for the WatchKit extension to launch the parent iOS app, send a request to the app and receive data in response once that request has been fulfilled.

This chapter will describe the way in which a WatchKit app extension can communicate directly with the parent iOS app. The next chapter (A WatchKit openParentApplication Example Project) will work through a tutorial that makes practical use of this technique.


Contents


Parent iOS App Communication

A WatchKit app implementation consists of the WatchKit app, the WatchKit app extension and the parent or containing iOS 8 app. When the user launches the WatchKit app on the Apple Watch device, the corresponding extension is launched on the iPhone device with which the watch is paired. In most cases, the WatchKit app extension contains all of the code that implements the logic and behavior of Watchkit app and this is often all that is needed to create a fully functional WatchKit app.

One characteristic of the WatchKit app extension that can make this configuration unsuitable for some requirements, however, is the fact that the extension is suspended when the user stops interacting with the corresponding WatchKit app on the watch device. In many instances this is not a problem unless the WatchKit app requires some task to continue running even when the user is no longer interacting with the app. Consider, for example, a WatchKit app designed to control the playback of music tracks on the iPhone device. If the audio playback is initiated from within the WatchKit app extension, the playback will stop when the WatchKit framework detects that the user is no longer using the WatchKit app on the watch. The app, on the other hand, requires the music to continue playing until the user requests that it stop by tapping a button on the WatchKit app. In such a scenario, the WatchKit extension clearly does not meet the needs of the app.

The solution to this dilemma is to hand off to the parent iOS app any tasks that need to continue to execute after the extension has been suspended. This can be achieved by making a call to the WatchKit framework openParentApplication class method from within the app extension.

The openParentApplication Method

When called, the openParentApplication method either wakes up or, if it is not already running, launches the parent iOS app such that it is executing in the background. In addition to launching the parent app, the method allows data to be passed to the parent app and to specify a block of code to be called and passed return data when the iOS app responds to the request.

The syntax for the openParentApplication method can be summarized as follows:

WKInterfaceController.openParentApplication(requestDictionary, 
	reply: { (replyDictionary, error) -> Void in
            // Code to be executed when parent app replies
   	})
}

The first point to note is that the openParentApplication method is a class method. As such it is called on the WKInterfaceController class rather than on an instance of the class. The first parameter to the method (named requestDictionary in the above example) is a Dictionary object containing any data that needs to be passed to the parent iOS app in order for the app to perform the necessary tasks.

The second parameter to the method is a closure expression containing the code that will be called and executed by the parent iOS app in order to reply to the openParentApplication call. When the closure expression is called it can be passed a Dictionary object (represented by replyDictionary in the above example) containing any data that needs to be returned to the extension together with an NSError object (or a nil value if no error occurred) used to report any problems encountered whilst the request was being fulfilled by the parent app.

The following code, for example, creates a dictionary containing a key-value pair and calls the openParentApplication method using a closure expression which outputs the value of the reply dictionary object based on a key of “replyString”:

let requestValues = ["myValue" : "startPlay"]

WKInterfaceController.openParentApplication(requestValues, 
	reply: { (replyValues, error) -> Void in
    println(replyValues["replyString"])
})

The handleWatchKitExtensionRequest Method

When the openParentApplication method is called, the handleWatchKitExtensionRequest method is called on the app delegate of the parent iOS app. This method is passed the Dictionary object declared in the openParentApplication method call and a reference to the reply closure expression.

The handleWatchKitExtensionRequest method will typically extract data from the dictionary, perform any necessary tasks, create a new dictionary populated with the reply data and then pass that through as a parameter when calling the reply closure expression. The following code shows an example implementation of the handleWatchKitExtensionRequest method:

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

    var replyValues = Dictionary<String, AnyObject>()
    replyValues["replyString"] = "Playback started"
    reply(replyValues)
}

Understanding iOS Background Modes

Although the parent iOS app is not automatically suspended when the user is no longer interacting with the matching WatchKit app, there are still situations where the iOS app running in the background may be suspended or terminated by the iOS operating system. There are a number of ways to mitigate this risk depending on whether the tasks being performed by the iOS app on behalf of the WatchKit app are short or long-term in nature.

Purchase the fully updated watchOS 2/Swift 2 edition of this book in eBook ($12.99) or Print ($27.99) format
watchOS 2 App Development Essentials Print and eBook (ePub/PDF/Kindle) editions contain 35 chapters.

Buy Print

Using the beginBackgroundTaskWithName Method

If the iOS app needs to perform a task which is short-term, and where suspension prior to replying to the WatchKit app would be detrimental to the user experience, the use of the UIApplication beginBackgroundTaskWithName and endBackgroundTask methods is recommended.

The beginBackgroundTaskWithName method indicates to the operating system that the app needs extra time to complete a task. The endBackgroundTask method is called to notify the operating system that the task is complete and that the application can be suspended. A background task request of this type does not provide an app with an indefinite amount of time to complete a task. When the operating system decides that sufficient time has been used, it will call the handler method declared when the beginBackgroundTaskWithName method was called to notify the app that the time has expired. The amount of time remaining can be checked at any time via the backgroundTimeRemaining property of the UIApplication instance. The following code, for example, might be placed within the handleWatchKitExtensionRequest method to request time to complete the designated task:

.
.
.
let bgIdentifier = application.beginBackgroundTaskWithName("MyTask", 
		expirationHandler: { () -> Void in
       // Code here will be called when time expires.
	// Perform any necessary clean up tasks here.
	// Report failure to complete task to app extension if 
	// necessary.
})

// Place code here to perform task on behalf of WatchKit app

reply(replyValues) // Reply to WatchKit App Extension

application.endBackgroundTask(bgIdentifier) // Notify OS of completion
.
.

Using Background Modes

For long-term background execution of an iOS app, Apple recognizes nine categories in which application suspension would be detrimental to the user experience, these being audio, location updates, voice over IP (VOIP), Newsstand updates, external and Bluetooth accessory communication, background fetch and remote notifications.

The background execution modes supported by an application are configured in the application’s Info.plist file using the UIBackgroundModes key. The value for the key is actually an array allowing an application to register for more than one background execution mode. The easiest way to enable the background modes required by an application is to select the application target at the top of the project navigator panel, select the Capabilities tab and switch the Background Modes option from Off to On. Once background modes are enabled, individual modes may be activated using the checkboxes provided as shown in Figure 12 1:


Setting the background modes for an WatchKit parent iOS app

Figure 12-1


With the necessary modes enabled, the app will not be suspended as long as it continues to perform tasks associated with the selected background mode. For example, as long as an iOS app configured for audio background mode continues to play music using the standard iOS frameworks it will not be suspended by the operating system.

Summary

Each WatchKit app has associated with it a WatchKit app extension which runs on the iPhone device while the user is using the app on the Apple Watch. When the user stops interacting with the app, the corresponding app extension is suspended by the operating system. This means that tasks that need to continue running after the extension is suspended need to be performed by the parent iOS app. This can be achieved using the openParentApp method. This method causes the parent iOS app to be woken up or launched in the background. The handleWatchKitExtensionRequest of the app delegate is called and passed a dictionary object containing data passed from the app extension. Once the iOS app has completed any required tasks it is able to reply to the app extension, passing through another dictionary object containing response data.

When using the iOS app to perform background tasks for a WatchKit app it is also important to be aware the iOS app may also be subject to suspension and termination. The risks of this can be reduced by making use of the various background task methods of the UIApplication instance, or the use of one or more the supported iOS app background modes.


Purchase the fully updated watchOS 2/Swift 2 edition of this book in eBook ($12.99) or Print ($27.99) format
watchOS 2 App Development Essentials Print and eBook (ePub/PDF/Kindle) editions contain 35 chapters.

Buy Print



PreviousTable of ContentsNext
A WatchKit Page-based Navigation TutorialA WatchKit openParentApplication Example Project