Continuity for iPhone and iPad with Handoff

12 February 2016

Starting from where we left off last week (Continuity for Apple Watch and iPhone with Handoff) we will be adding Handoff support to our Counties sample application to allow transferring tasks between the iPhone and iPad. Before reading this post familiarise yourself with last week's as it provides the basis for the technique that will be discussed in this article.

To recap, Continuity describes a set of technologies that allow users of iOS and Mac OS devices to begin tasks on one device and then transfer to a new device to continue with that task. Last week we added Continuity between the iPhone and Apple Watch using Handoff; specifically we used the NSUserActivity class to transfer details about viewing a county on the watch to the iPhone. Today we will be using the same technique to transfer the same activity from the iPhone to the iPad.

NSUserActivity on iOS

Unlike our Apple Watch example, on iOS we have to explicitly create a user activity when the user views a county on their iPhone. Fortunately this is a quick and easy process. We want to broadcast when a user views a county, so in our CountyViewController we simply add the following:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // View configuration code omitted
    
    userActivity = NSUserActivity(activityType: "com.darjeeling.counties.handoff.countydetails")
    userActivity?.userInfo = ["CountyName": county.name]
}

UIResponder has a userActivity property, which our view controller inherits. We simply create a user activity and populate its userInfo with the details of the county that the user is viewing. In your own apps you will populate the userInfo dictionary with whatever information is required to recreate your activity on another device.

Notice that although NSUserActivity has methods for becoming the current activity, and for resigning the current activity, we do not have to call these ourselves. This is managed for us by the responder chain, so while the view controller is the responder furthest down the chain with an associated activity then that activity is current. Also, when the view controller is deallocated when the user stops viewing the county details the activity automatically resigns as the current activity and is no longer broadcast to other devices.

Updating Activities

If the activity that you broadcast contains details that the user enters manually, such as filling out a form with text, then you will want to update the activity periodically to make sure that this information is transferred to another device in the event of Handoff being used. Do not trigger updates yourself, but instead implement UIResponder's updateUserActivityState(activity:) method, which iOS will call periodically to provide you with a chance to update the activity.

Receiving an Activity

On the iPad, we receive an activity in the same way as we received an activity on the iPhone that was transferred from the watch. We implement application(application:continueUserActivity:restorationHandler:) in our app delegate to handle the activity that is passed from the phone:

func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
    guard let userInfo = userActivity.userInfo, countyName = userInfo["CountyName"] as? String, selectedCounty = County.allCounties.filter({$0.name == countyName}).first else where userActivity.activityType == "com.darjeeling.counties.handoff.countydetails" {
        return false
    }
    showCounty(selectedCounty)
    return true
}

This is exactly the same code that we used to handle Handoff of activities from Apple Watch on the iPhone - as long as we use the same activity type and userInfo then we don't need to write any extra handling code.

Handoff In Action

Now that we have all of the code in place, let's take a look at how Handoff works. First we view a county on the iPhone:

Viewing Hertfordshire on iPhone.
Viewing Hertfordshire on iPhone.

Next we take a look at our iPad's lock screen:

The iPad lock screen with the Counties app being shown for Handoff.
The iPad lock screen with the Counties app being shown for Handoff.

Notice the Counties app icon is shown in the bottom left corner of the lock screen:

Close up of the Handoff icon on the iPad lock screen.

Swiping up from this icon launches the Counties app on the iPad, and takes us to the county we were viewing on iPhone:

Hertfordshire details being shown on iPad.
Hertfordshire details being shown on iPad.

Conclusion

As you can see from the code above and the previous article, the code required to enable Handoff is minimal and simple to setup. Once again I encourage you to check out the sample project yourself to get a feel for how easy it is to enable Handoff in your own apps.

One More Thing

As the code running on the iPhone and iPad is identical, we also get support for handing off activities from the iPad to the iPhone for free, with no extra code required. This allows a user to carry out a complex task using their large screened iPad and then take the results with them by handing the task off to iPhone.