My iOS app was advertising its Handoff activity to its Mac counterpart just fine. The reverse just would not happen. 11 back and forth TSI emails later, we figured it out. Now I feel like sharing!
Step #0: Debug Build
Just do a normal Debug build. There’s no need to use Release, pick distribution identities, exporting, etc. to enable Handoff.
Step #1: Activity Types
This is trivial, and you probably have this down already: both versions must use the same
activityType, and they both must have a
NSUserActivityTypes array key in
Info.plist, containing that same
Step #2: Sandbox (OS X)
Your Mac app must be sandboxed. Turn on
App Sandbox in the
Capabilities tab of your OS X target.
Step #3: No Developer ID (OS X)
Here’s a warning, straight from the mothership:
It is a known bug that Developer-Id signed apps do not work with Handoff.
You heard the man: do not sign with Developer ID.
Step #4: Code Signing Identity
Instead, for your Debug builds, sign with an App Store development certificate, a.k.a. “identity”.
On OS X, those certificates’ names start with
Mac Developer: ....
On iOS you’re probably OK, but just in case, use one that starts with
iOS Development: ....
Step #5: Provisioning Profile
Both apps [must be] signed by the same team ID
This is where I had it wrong.
Apparently, Team IDs for development certificates are, er… random? But that’s okay. What seems to count (for Handoff, at least) is the Team ID from the provisioning profile used to sign the app. Or more precisely, the corresponding entitlement that is generated.
You can use this command to verify that the entitlement is present:
codesign -dvv --entitlements - yourapp.app
You’re looking for the
Make sure it’s there, and that the Team ID it shows is correct.
If it’s missing or incorrect, I suggest you manually select a
Provisioning Profile in your build settings. In my case, automatic provisioning profile selection was failing - possibly because of the random Team IDs (?).
Step #6: If Everything Fails (OS X)
Regenerate your development certificate and provisioning profile, and then select them in your build settings. Apparently, some old ones are busted in some mysterious way.
Bonus #1 (OS X)
If you’re having trouble closing windows in your app in Release builds, or seeing this in Console:
Cannot update for observer <NSUIActivityResponderMonitor 0x60800000a230> for the key path “mainWindow.firstResponder” from <NSApplication 0x6000001181e0>, most likely because the value for the key “mainWindow” has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the NSApplication class.
You can work around this by avoiding the
userActivity property of
NSResponder. Instead, create and keep around your own
let handoffActivity = NSUserActivity(activityType: "com.example.app.activity")
And manually call
becomeCurrent() on it when appropriate. You can still use the
handoffActivity.needsSave = true handoffActivity.delegate = self handoffActivity.becomeCurrent()
Not as elegant as the responder chain way, but it works.
I don’t know what’s causing this, but I’ve filed Radar #19138455. I’ll update this article when the issue is resolved.
Bonus #2 (OS X)
You can get more Console logging from
sharingd (the deamon responsible for Handoff, among other things), by restarting it after setting this sneaky hidden preference flag:
defaults write com.apple.Sharing EnableDebugLogging -bool TRUE
Hope this helps! Let me know if you’re still having problems.