Active Filters: Continuity

We first looked at Handoff and NSUserActivity all the way back in Bite #29. Today we'll take a look at a new addition to NSUserActivity in iOS 10 that allows our apps to share more about the user's current context with other parts of the system. Let's dive in. 🏊

Let's imagine our app lets users view a list of Robot Stores. We'll start by re-using a technique we first learned about in Bite #47, MKLocalSearch.

First we'll create an MKLocalSearchRequest to find all the Robot Store locations within a reasonable radius of the user's current location (acquired off-camera via standard Core Location mechanisms):

let request = MKLocalSearchRequest()

request.naturalLanguageQuery = "Robot Store"
request.region = MKCoordinateRegionMakeWithDistance(
  usersCurrentLocation, 1600, 1600)

Next, we'll start an MKLocalSearch using our request, and load a bunch of mapItems representing Robot Store locations near us.

If we were building a complete app, this is the part where we'd grab the response.mapItems from above, map their values into some business objects, then display them probably in UITableView, etc.

For now, let's simply try out the new feature of NSUserActivity.

MKLocalSearch(request: request).start { (response, error) in
  guard error == nil else { return }
  guard let response = response else { return }

  guard let exampleMapItem = response.mapItems.first else { return }

  let activity = NSUserActivity(activityType: "com.robots-store.shopping-locally")

  activity.title = exampleMapItem.name
  activity.mapItem = exampleMapItem

  self.userActivity = activity
}

Finally, we can run our app, double tap our home button and see the results:

Success!

Topics

#29: Handoff 👋

Topics

Handoff is part of Apple's Continuity system. It allows users to begin a task or activity on one device, then continue it on another one. It's actually extremely simple to implement, all you do is tell the system what the user is currently doing in your app, and the system handles the rest. Here it is in code:

class EditSpaceshipViewController: UIViewController {
  func createActivity() {
    let activity = NSUserActivity(
      activityType: "com.littlebites.spaceships"
    )

    activity.title = "Edit Spaceship"

    activity.addUserInfoEntriesFromDictionary([
      "spaceshipID" : spaceship.spaceshipID
    ])

    activity.becomeCurrent()
  }

  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    createActivity()
  }
}

Now, if the user picks up another device the activity your app's icon will appear in the bottom left of the user's lock screen on iOS, or in the dock on OS X, and the user can continue where they left off. To wrap things up, we just need to implement two additional UIApplicationDelegate methods:

func application(application: UIApplication, willContinueUserActivityWithType userActivityType: String) -> Bool {

  return true
}

func application(application: UIApplication,  continueUserActivity userActivity: NSUserActivity,  restorationHandler: ([AnyObject]?) -> Void) -> Bool {

  // use the userActivity object to restore the state
  // needed for the user to continue what they were doing

  return true
}