iOS 10 测试版推送通知的一个小坑
背景:
应用收到推送通知后,通过 application:didReceiveRemoteNotification:fetchCompletionHandler: 方法,响应推送通知的点击。测试发现在 iOS 10 上面虽然能收到推送,但是点击通知中心的消息进入应用后,应用没有跳转到消息页面。
详情:
调试时发现,iOS 处理推送通知的方式在 iOS 9 和 iOS 10 上面有所不同。接收消息推送有两个代理方法:
方法 1:application:didReceiveRemoteNotification:
方法 2:application:didReceiveRemoteNotification:fetchCompletionHandler:
当同时实现方法两个方法时,应用在不同状态下调用的方法不一致。
一般应用有三种状态:
a)应用未启动;
b)应用已启动,但处于后台;
c)应用处于前台。
对于以上三种状态,iOS 9 在收到消息通知后都会调用方法 2,这也符合官方文档的描述。然而对于 iOS 10,当应用处于 a 或 b 状态时,调用方法 1,当应用处于 c 状态时,调用方法 2。
然而官方文档对于这两个方法的描述,是这样的:
Let’s review the possible scenarios that can arise when the system delivers a local notification or a remote notification for an app.
The notification is delivered when the app isn’t running in the foreground.In this case, the system presents the notification, displaying an alert, badging an icon, perhaps playing a sound, and perhaps displaying one or more action buttons for the user to tap.
The user taps a custom action button in an iOS 8 notification.In this case, iOS calls either application:handleActionWithIdentifier:forRemoteNotification:completionHandler:or application:handleActionWithIdentifier:forLocalNotification:completionHandler:. In both methods, you get the identifier of the action so that you can determine which button the user tapped. You also get either the remote or local notification object, so that you can retrieve any information you need to handle the action.
The user taps the default button in the alert or taps (or clicks) the app icon.If the default action button is tapped (on a device running iOS), the system launches the app and the app calls its delegate’s application:didFinishLaunchingWithOptions:method, passing in the notification payload (for remote notifications) or the local-notification object (for local notifications). Although application:didFinishLaunchingWithOptions:isn’t the best place to handle the notification, getting the payload at this point gives you the opportunity to start the update process before your handler method is called.
For remote notifications, the system also calls the application:didReceiveRemoteNotification:fetchCompletionHandler:method of the app delegate.
If the app icon is clicked on a computer running OS X, the app calls the delegate’s applicationDidFinishLaunching:method in which the delegate can obtain the remote-notification payload. If the app icon is tapped on a device running iOS, the app calls the same method, but furnishes no information about the notification.
The notification is delivered when the app is running in the foreground.The app calls the application:didReceiveRemoteNotification:fetchCompletionHandler:or application:didReceiveLocalNotification:method of the app delegate. (If application:didReceiveRemoteNotification:fetchCompletionHandler:isn’t implemented, the system calls application:didReceiveRemoteNotification:.) In OS X, the system calls application:didReceiveRemoteNotification:
另外,在 方法 1 SDK的描述中,苹果是这么说的:
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler:method instead of this one whenever possible. If your delegate implements both methods, the app object calls the application:didReceiveRemoteNotification:fetchCompletionHandler: method.
结论:
目前 iOS 10 测试版的推送通知处理与文档中描述的有出入,这可能是测试版的问题,后续是否能够更改未知,因此,目前最保险的方法就是,在 application:didFinishLaunchingWithOptions: 以及上述两个方法中都检测是否存在推送通知,并进行处理。
测试使用的 iOS 10 版本为 10.0 (14A5335b),测试手机为 iPhone 6,对于这个问题的其他相关描述:
1)http://www.heapoverflow.me/question-handeling-user-notifications-on-ios-10-38940193
2)http://www.openradar.me/27194349
问题还在跟进中,随时变更。