About Handoff

Handoff is a capability introduced in iOS 8 and OS X v10.10 that transfers user activities among multiple devices associated with the same user. In iOS 9 and OS X v10.11, Handoff helps your app participate in search by making it possible to designate user activities and app states as searchable. For example, when a searchable activity or state appears in Spotlight search results or Siri suggestions, users can tap the result to return to the relevant area in your app.

Handoff lets users switch from one device to another and continue an ongoing activity seamlessly, without reconfiguring each device independently. For example, a user who is browsing a long article in Safari on a Mac can move to a nearby iOS device that’s signed into iCloud with the same Apple ID and open the same webpage automatically in Safari on iOS, at the same scroll position as on the original device.

../Art/continuation_2x.png

Apple apps, such as Safari, Mail, Maps, Contacts, Notes, Calendar, and Reminders use public APIs to implement Handoff for iOS 8 and OS X v10.10. A third-party developer can use the same APIs to implement Handoff in apps that share the developer’s Team ID. Such apps must either be distributed through the App Store or signed by the registered developer.

Handoff Interactions

Handing off a user activity involves three phases:

Document-based apps (that is, apps based on a subclass of NSDocument or UIDocument), provide built-in support for all three phases of the handoff scenario. Responder objects (subclasses of NSResponder and UIResponder) provide built-in support for updating user activities and managing their current status. Your app can also create, update, and continue user activities directly, working especially with the app delegate.

The Handoff mechanism depends primarily on objects of a single class in Foundation, NSUserActivity, with support of additional small APIs in UIKit and AppKit. Apps encapsulate information about a user’s activities in NSUserActivity objects, and those activities become candidates for continuation on other devices. Handoff of a given user activity requires the originating app to designate that activity’s NSUserActivity object as the current activity, save pertinent data for continuation on another device, and send the data to the resuming device. Handoff passes only enough information between the devices to describe the activity itself, while larger-scale data synchronization is handled through iCloud.

On the continuing device, the user is notified that an activity is available for continuation. If the user chooses to continue the activity, an appropriate app is launched and provided with the activity’s payload data. A user activity can be continued only in an app that has the same developer Team ID as the activity's source app and that supports the activity's type. Supported activity types are specified in the app's Info.plist under the NSUserActivityTypes key (for more information about this key, see NSUserActivityTypes). So, the continuing device chooses the appropriate app based on the target Team ID, activity type property of the originating NSUserActivity object, and optionally the activity object’s title property. From the information in the user activity object’s userInfo dictionary, the continuing app can then configure its user interface and state appropriately for seamless continuation of the user’s activity.

Optionally, if continuing an activity requires more data than can be efficiently transferred by the initial transport mechanism, a resuming app can call back to the originating app’s activity object to open streams between the apps and transfer more data. For example, if the activity to be continued is composing an email message that contains an image, then the streams option is the best way to transfer the data needed to continue the composition on another device. For more information, see Using Continuation Streams.

Document-based apps on iOS and OS X automatically support Handoff, as described in Supporting a User Activity in Document-Based Apps.

User Activity Object

An NSUserActivity object encapsulates the state of a user activity in an app on a particular device. It is the primary object in the Handoff mechanism and it helps you designate an activity or app state as searchable. The originating app creates a user activity object for each user activity that can be handed off to another device or that can appear in Spotlight search results. For example, a web browser would create a user activity object for each open tab or window in which the user is browsing URLs. However, only the activity object corresponding to the frontmost tab or window is current at a given time, and only the current activity is available for continuation.

An NSUserActivity object is identified by its activityType and title properties. In addition, you can use properties such as keywords and contentAttributeSet to provide rich information about an activity to display in search results.

The NSUserActivity class defines properties you use to specify the eligibility of an activity for various uses. For example, you can use eligibleForSearch to add an activity to the on-device index and enable it to show up in the user’s search results and you can use expirationDate to specify a date after which an activity is no longer eligible to be indexed or handed off.

An NSUserActivity object also has a userInfo dictionary to contain its state data and a flag named needsSave that supports lazy updating of its state by its delegate. The NSUserActivity method addUserInfoEntriesFromDictionary: enables the delegate and other clients to merge state data into its userInfo dictionary.

For more information, see NSUserActivity Class Reference.

User Activity Delegate

The user activity delegate is an object that conforms to the NSUserActivityDelegate protocol. It is typically a top-level object in the app, such as a view controller or the app delegate, that manages the activity’s interaction with the app.

The user activity delegate is represented by the delegate property of NSUserActivity and is responsible for keeping the data in the NSUserActivity object’s user info dictionary up to date so that it can be handed off to another device. When the system needs the activity to be updated, such as before the activity is continued on another device, it calls the delegate’s userActivityWillSave: method. You can implement this callback to make updates to the object’s data-bearing properties such as userInfo, title, and so on. Once the system calls this method, it resets needsSave to NO. Change this value to YES if something happens that changes the userInfo or other data-bearing properties again.

Alternatively, instead of implementing the delegate’s userActivityWillSave: method, you can have UIKit or AppKit manage the user activity automatically. The app opts into this behavior by setting a responder object’s userActivity property and implementing the responder’s updateUserActivityState: callback, as described in Managing a User Activity With Responders. This arrangement is preferred if it works for your user activity.

For more information, see NSUserActivityDelegate Protocol Reference.

App Framework Support

UIKit and AppKit provide support for Handoff in the document, responder, and app delegate classes. Although there are minor behavioral differences between the platforms, the basic mechanism, which enables apps to save and restore user activities, is the same, and the APIs are the same.

Supporting a User Activity in Document-Based Apps

A document-based app on iOS and OS X automatically supports Handoff if you add an NSUbiquitousDocumentUserActivityType key and value for each CFBundleDocumentTypes entry in your app’s Info.plist property list file. If this key is present, NSDocument and UIDocument automatically create NSUserActivity objects for iCloud-based documents of the given document type. The value of NSUbiquitousDocumentUserActivityType is a string that represents the NSUserActivity object’s activity type. That is, you provide an activity type for each document type supported by your document-based app. Multiple document types can have the same activity type. NSDocument and UIDocument automatically put the value of their fileURL property into the activity object’s userInfo dictionary with the NSUserActivityDocumentURLKey.

In OS X, AppKit can automatically restore NSUserActivity objects created in this way. It does so if the app delegate method application:continueUserActivity:restorationHandler: returns NO or is unimplemented. In this situation, the document is opened with the NSDocumentController method openDocumentWithContentsOfURL:display:completionHandler: and receives a restoreUserActivityState: message.

For more information, see Adopting Handoff in Document-Based Apps. Also see NSDocument Class Reference and UIDocument Class Reference.

Managing a User Activity with Responders

UIKit and AppKit can manage a user activity if you set it as a responder object’s userActivity property. When the responder knows that the activity state is dirty, it must set the object’s needsSave property to YES. The system automatically saves the NSUserActivity object at appropriate times, first giving the responder an opportunity to update the activity’s state through the updateUserActivityState: callback. Your responder subclass must override the updateUserActivityState: method to add state data to the user activity object. If multiple responders share a single NSUserActivity object, they all receive an updateUserActivityState: callback when the system updates the user activity object. Before the update callbacks are sent, the activity object’s userInfo dictionary is cleared.

In OS X, NSUserActivity objects managed by AppKit and associated with responders automatically become current based on the main window and the responder chain, that is, when the document’s window becomes the main window. In iOS, however, for NSUserActivity objects managed by UIKit, you must either call becomeCurrent explicitly or have the document’s NSUserActivity object set on a UIViewController object that is in the view hierarchy when the app comes to the foreground.

A responder can set its userActivity property to nil to disassociate itself from an activity. When an NSUserActivity object managed by the app framework has no more associated responders or documents, it is automatically invalidated.

For more information, see Adopting Handoff in Responders. Also see NSResponder Class Reference or UIResponder Class Reference.

Continuing an Activity Using the App Delegate

The app delegate is the primary entry point for continuing a user activity in a non-document-based app. As soon as the user chooses to resume an activity, either by responding to the notification or by selecting a search result, Handoff launches the appropriate app and sends the app’s delegate an application:willContinueUserActivityWithType: message. The app lets the user know that the activity will continue shortly. Meanwhile, the NSUserActivity object is delivered when the delegate receives an application:continueUserActivity:restorationHandler: message. You should implement this method to configure your app in such a way that it can resume the activity represented by the user activity object.

The application:continueUserActivity:restorationHandler: message includes a block, the restoration handler, that you can optionally call if your app uses auxiliary responder or document objects to perform the resuming user activity. Create these objects (or fetch them if cached) and pass them to the restoration handler in its NSArray parameter. The system then sends each object a restoreUserActivityState: message, passing the user activity object. Each object can use the activity’s userInfo data to resume the activity. For more information about using this restoration handler, see the description of the application:continueUserActivity:restorationHandler: method in NSApplicationDelegate Protocol Reference.

When you continue an activity that was chosen in a search result, you should regenerate the keywords for the activity, if appropriate, because the activity you receive may not have the same properties as the activity that was originally created.

If you do not implement application:continueUserActivity:restorationHandler: or return NO from it, and your app is document-based, AppKit can automatically resume the activity, as described in Supporting User Activity in Document-Based Apps. For more details, see Continuing an Activity.