Tomasz Szulc
Tomasz Szulc

Reputation: 4235

Handoff does not work with iOS 9 devices

Trying to force Handoff functionality to work on iPhone 5 and iPad Air with iOS 9 devices and encounter issues that I think is iOS9-related - cannot check on iOS 8 because I have no devices with this system.

Problem:

  1. I am opening app on first device when main screen when user activity is created
  2. On second device I see on lock screen that there is some activity related to my app
  3. I am opening this app and application:continueUserActivity:restorationHandler: is not called on this device so I have no ability to show to user the same content which was presented on the first device.

You can browse entire project on github: https://github.com/tomkowz/Quotes

Implementation details:

I've updated target's plist file and added NSUserActivityTypes.

<key>NSUserActivityTypes</key>
<array>
    <string>com.tomaszszulc.Quotes.quotesList</string>
    <string>com.tomaszszulc.Quotes.browseQuote</string>
</array>

Next I've created enum with these declared types:

enum ActivityType: String {
    case BrowseQuote = "com.tomaszszulc.Quotes.browseQuote"
    case QuotesList = "com.tomaszszulc.Quotes.quotesList"
}

When user is on the main screen I'm starting NSUserActivity.

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    quotes = Quote.findAll(CoreDataStack.sharedInstance().mainContext)
    tableView.reloadData()
    startUserActivity()
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    userActivity?.invalidate()
}

func startUserActivity() {
    let activity = NSUserActivity(activityType: ActivityType.QuotesList.rawValue)
    activity.title = "Viewing Quotes List"
    userActivity = activity
    userActivity?.becomeCurrent()
}

The second type of activity activates when user goes to details of selected item. Here is the views flow:

UINavigationController -> (root) QuotesListViewController -> (push) QuoteDetailsViewController

Here is the code for creating user activity in QuoteDetailsViewController:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    userActivity = viewModel.userActivity // (viewModel) quote.userActivity
    userActivity?.becomeCurrent()
}

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    userActivity?.invalidate()
}

And the viewModel.userActivity calls:

extension Quote {
    @available(iOS 8.0, *)
    var userActivity: NSUserActivity {
        let activity = NSUserActivity(activityType: ActivityType.BrowseQuote.rawValue)
        activity.title = "Reading " + self.author + " quote"
        activity.userInfo = [QuoteUserActivityKey.Identifier.rawValue: self.identifier]
        // Core Spotlight support
        if #available(iOS 9.0, *) {
            activity.contentAttributeSet = self.searchableItemAttributeSet()
            activity.keywords = Set([self.author])
            activity.eligibleForSearch = true
            activity.eligibleForHandoff = true
        }

        return activity
    }
}

Thank you in advance!

Upvotes: 0

Views: 915

Answers (1)

Richard
Richard

Reputation: 1268

If you are getting the indicator on the second device that it is seeing the potential handoff, then the only "good" reason why application:continueUserActivity:restorationHandler:isn't called is:

This method is not called if either application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: returns NO.

The other reason handoff "doesn't work" is if the devices are not logged to the same iCloud account. But you see the indicator, so that is not it in your case.

Upvotes: 1

Related Questions