Episode #192

Handoff

14 minutes
Published on October 8, 2015

This video is only available to subscribers. Get access to this video and 572 others.

Supporting Handoff in your iOS / Mac applications can really delight users. In this episode we will build handoff support into an application so that users can continue their task on the web, or in a separate Mac application that is registered to handle that task.

Episode Links

Info.Plist Settings

<key>NSUserActivityTypes</key>
<array>
    <string>com.nsscreencast.videoplay</string>
</array>

These need to be registered on applications that can handle those activities. It is not necessary for the producing application to also declare these, but if you want bi-directional handoff, then you would add this to both applications.

Registering a user activity

let activity = NSUserActivity(activityType: "com.nsscreencast.videoplay")
activity.title = "Watch episode 187"
activity.userInfo = [
    "foo": "bar"
]
activity.webpageURL = NSURL(string: "https://www.nsscreencast.com/episodes/187")!
activity.delegate = self
activity.becomeCurrent()

playerVC.userActivity = activity
player.play()

Updating user info for a user activity

First we need to tell the activity that it needs to save...

        let interval = CMTimeMakeWithSeconds(1, 1)
        player.addPeriodicTimeObserverForInterval(interval, queue: nil) { time in
            print("Time: \(CMTimeGetSeconds(time))")
            if let activity = playerVC.userActivity {
                activity.needsSave = true
            }
        }

Then we can get notified just before the save actually happens, to update the userInfo with our current state:

    func userActivityWillSave(userActivity: NSUserActivity) {

        if let time = playerVC?.player?.currentTime() {
            let seconds = Int(CMTimeGetSeconds(time))
            userActivity.addUserInfoEntriesFromDictionary([
                "startTime": "\(seconds)"
            ])
        }
    }

Handling App Activation via Handoff

  func application(application: NSApplication, willContinueUserActivityWithType userActivityType: String) -&gt; Bool {
        print("willContinueUserActivityWithType: \(userActivityType)")
        return true
    }

    func application(application: NSApplication, didFailToContinueUserActivityWithType userActivityType: String, error: NSError) {
        print("didFailToContinueUserActivity: \(error)")
    }

    func application(application: NSApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]) -&gt; Void) -&gt; Bool {
        print("Continue activity: \(userActivity.userInfo)")
        return true
    }