Handoff Tutorial: Getting Started
Learn how to use the new Handoff API introduced in iOS 8 to allow users to continue their activities across different devices. By Soheil Azarpour.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Handoff Tutorial: Getting Started
35 mins
- Handoff Overview
- Getting Started
- Device Compatibility: iOS
- User Activities
- Activity Types
- The Starter Project
- Setting Your Team
- Configuring Activity Types
- Quick End-to-End Test
- Creating the View Activity
- Finishing Touches
- Creating the Edit Activity
- Finishing Touches
- Receiving the Activities
- Finishing Touches
- Versioning Support
- Handoff Best Practices
- Where To Go From Here?
Update 04/23/2015: Updated for Xcode 6.3 and Swift 1.2.
Note from Ray: This is an abbreviated version of a chapter from iOS 8 by Tutorials released as part of the iOS 8 Feast to give you a sneak peek of what’s inside the book. We hope you enjoy!
Handoff is a new feature in iOS 8 and OS X Yosemite. Handoff lets you continue an activity uninterrupted when you switch from one device to another – without the need to reconfigure either device.
You can add handoff feature to your iOS and OS X apps in iOS 8 and Yosemite. In this tutorial you’ll learn the basic workings of Handoff and how to use it on iOS with a non-document-based app.
Handoff Overview
Before you dive into the code, it’s important to get a high level overview of some important Handoff concepts:
- Getting Started: Learn if your devices are Handoff-compatible and run a basic test to make sure things are working.
- User Activities: Learn about the core unit of work with Handoff: user activities.
- Activity Types: Learn how you can set an “activity type” on a user activity and what that means.
Getting Started
Not only can Handoff transfer your current activity from an iOS to an OS X device, but it can also transfer your current activity between iOS devices.
At the time of writing this tutorial, Handoff does not work on the iOS simulator. Therefore, to follow along with this tutorial, you will need two Handoff-compatible iOS devices.
Device Compatibility: iOS
To check whether your iOS device is Handoff compatible, go to Settings and select General from the list. If you see Handoff & Suggested Apps in the list, your device is Handoff compatible. The following screenshots show General settings menu of an iPhone 5s (Handoff compatible) and an iPad 3rd Gen (not Handoff compatible), respectively.
Handoff functionality depends on few things:
- An iCloud account: You must be logged in to the same iCloud account on each device you wish to use Handoff.
- Bluetooth LE 4.0: Handoff broadcasts activities via Bluetooth LE signals, so both the broadcasting and receiving devices must have Bluetooth LE 4.0 support.
- iCloud paired: Devices should have been already paired through iCloud. When you sign into your iCloud account on Handoff compatible devices, each device is paired with other Handoff compatible devices. This is where the magic happens.
At this time, make sure that you have two Handoff compatible devices running iOS 8 or later that are logged onto the same iCloud account.
User Activities
Handoff is based on the concept of a user activity, which is a stand-alone collective unit of information that can be handed off without any dependencies on any other information.
The NSUserActivity
class represents an instance of a user activity. It encapsulates the state of the application in a way that can be continued on other devices in a related application.
There are three ways to interact with NSUserActivity
objects:
You can use the userInfo
dictionary of NSUserActivity
to pass native data types or NSCoding
-compliant custom objects to the receiving device. Native data types include NSArray
, NSData
, NSDate
, NSDictionary
, NSNull
, NSNumber
, NSSet
, NSString
, NSUUID
, and NSURL
. Passing NSURL
can be a bit tricky; check out the Best Practices section of this tutorial before using NSURL
with Handoff.
Notice that you don’t set userInfo
to a new dictionary or update it directly. Instead, you should use the convenience method addUserInfoEntriesFromDictionary()
.
Later in this tutorial, you’ll learn how to force the user activity to refresh on demand, or how to get a similar callback at the app delegate level.
You can then use the data stored in the NSUserActivity
object to re-create the user’s activity. This is where you will update your app so that it can continue the associated activity.
-
Create user activity: The originating app creates an
NSUserActivity
and callsbecomeCurrent()
on it to start the broadcasting process. Here’s a quick example:let activity = NSUserActivity(activityType: "com.razeware.shopsnap.view") activity.title = "Viewing" activity.userInfo = ["shopsnap.item.key": ["Apple", "Orange", "Banana"]] self.userActivity = activity; self.userActivity?.becomeCurrent()
You can use the
userInfo
dictionary ofNSUserActivity
to pass native data types orNSCoding
-compliant custom objects to the receiving device. Native data types includeNSArray
,NSData
,NSDate
,NSDictionary
,NSNull
,NSNumber
,NSSet
,NSString
,NSUUID
, andNSURL
. PassingNSURL
can be a bit tricky; check out the Best Practices section of this tutorial before usingNSURL
with Handoff. -
Update user activity: Once an instance of
NSUserActivity
becomes current, the OS periodically invokesupdateUserActivityState(activity:)
on your topmost view controller to give you a chance to update the user activity. Here’s an example:override func updateUserActivityState(activity: NSUserActivity) { let activityListItems = // ... get updated list of items activity.addUserInfoEntriesFromDictionary(["shopsnap.item.key": activityListItems]) super.updateUserActivityState(activity) }
Notice that you don’t set
userInfo
to a new dictionary or update it directly. Instead, you should use the convenience methodaddUserInfoEntriesFromDictionary()
.Later in this tutorial, you’ll learn how to force the user activity to refresh on demand, or how to get a similar callback at the app delegate level.
-
Receive user activity: When your receiving app launches with a user activity from Handoff, the app delegate calls
application(:willContinueUserActivityWithType:)
. Note this method is not passed an instance ofNSUserActivity
, because it takes a while until Handoff downloads and transfers theNSUserActivity
data to your app.Later on, the following delegate callback invokes once the user activity has been downloaded:func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: (([AnyObject]!) -> Void)) -> Bool { // Do some checks to make sure you can proceed if let window = self.window { window.rootViewController?.restoreUserActivityState(userActivity) } return true }
You can then use the data stored in the
NSUserActivity
object to re-create the user’s activity. This is where you will update your app so that it can continue the associated activity.
let activity = NSUserActivity(activityType: "com.razeware.shopsnap.view")
activity.title = "Viewing"
activity.userInfo = ["shopsnap.item.key": ["Apple", "Orange", "Banana"]]
self.userActivity = activity;
self.userActivity?.becomeCurrent()
override func updateUserActivityState(activity: NSUserActivity) {
let activityListItems = // ... get updated list of items
activity.addUserInfoEntriesFromDictionary(["shopsnap.item.key": activityListItems])
super.updateUserActivityState(activity)
}
func application(application: UIApplication,
continueUserActivity userActivity: NSUserActivity,
restorationHandler: (([AnyObject]!) -> Void))
-> Bool {
// Do some checks to make sure you can proceed
if let window = self.window {
window.rootViewController?.restoreUserActivityState(userActivity)
}
return true
}