推送通知处理

38

我正在阅读苹果文档关于

处理本地和远程通知

对我来说,它似乎有矛盾的陈述。可以有人澄清这些混淆点吗?现在让我们严格谈论远程通知(而不是本地通知)。

文档说,如果通知上的操作按钮被按下,它会调用application:didFinishLaunchingWithOptions并传递通知负载。稍后它说,如果应用程序在前台运行,则通过application:didReceiveRemoteNotification:传递通知。这暗示着当应用程序处于后台或未运行时,将调用application:didFinishLaunchingWithOptions。否则,将调用application:didReceiveRemoteNotification:。

稍后,有一个iOS注释,内容如下:

在iOS中,您可以通过检查应用程序状态来确定应用程序是由用户点击操作按钮启动还是通过向已运行的应用程序传递通知而启动。在委托的application:didReceiveRemoteNotification:或application:didReceiveLocalNotification:方法的实现中,获取applicationState属性的值并评估它。如果值为UIApplicationStateInactive,则表示用户点击了操作按钮;如果值为UIApplicationStateActive,则表示当应用程序接收到通知时,应用程序位于最前面。
这对我意味着当应用程序已经在前台运行时,以及用户按下操作按钮(或在iOS 5中滑动操作滑块)将应用程序置于前台/启动应用程序时,都会调用application:didReceiveRemoteNotification:。
我的困惑可能源于文档中暗示通知负载是通过application:didFinishLaunchingWithOptions:方法发送的,或者对“运行中”应用程序的误解(后台应用程序是否被认为是“运行中”?)。 application:didReceiveRemoteNotification:的文档说明它适用于“正在运行”的应用程序。
因此,总结一下,我可以得到以下澄清:

1) 当应用程序处于前台或用户选择“操作”通知时,是否总是调用application: didReceiveRemoteNotification:?如果不是,我们如何理解iOS注释中关于确定应用程序状态为活动或非活动的说明?

2) 从文档声称application: didReceiveRemoteNotification被调用的角度来看,后台应用程序是否“正在运行”?

3) 为了完整起见,后台应用程序是UIApplicationStateInactive还是Active?


20
我能获得核对标记吗? - ch3rryc0ke
2个回答

91

这里的措辞有些令人困惑,特别是涉及到"backgrounding"这个词。

当应用程序确实未加载到内存中(例如,当您启动它时,会显示出闪屏等),那么将调用application:didFinishLaunchingWithOptions方法,并且您可以按照以下方式获取推送通知:

NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

if(remoteNotif)
{
    //Handle remote notification
}

如果应用程序已加载到内存中并处于活动状态(例如,该应用程序当前在设备上打开),则只调用application:didReceiveRemoteNotification:

如果应用程序已加载到内存中但不是活动状态且未后台运行(例如,您启动了应用程序,然后按下Home按钮,并等待10秒钟),然后单击推送通知上的操作按钮,则仅会调用 didReceiveRemoteNotification

您可以按以下方式捕获此情况:

-(void)application:(UIApplication *)app didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if([app applicationState] == UIApplicationStateInactive)
    {
        //If the application state was inactive, this means the user pressed an action button
        // from a notification. 

    //Handle notification
    }
}

2
在您所解释的第一种情况下,didReceiveRemoteNotification方法会被调用吗?在您编写的两个方法中实现我的代码就足够了吗?不会导致代码运行两次吗?谢谢。 - mcont
1
这是不正确的:如果您有通知中心或控制中心等可见,该应用程序将被视为非活动状态。您对如何确定“从后台变为活动状态”的类型有任何建议吗? - dvkch
请注意,相同的行为也与didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result)) NS_AVAILABLE_IOS(7_0)有关。 - valvoline
这里有一个很好的答案,似乎处理了一些其他问题:https://dev59.com/Q2025IYBdhLWcg3wtofX,基本上是检查应用程序是否处于非活动或后台状态:if(state == UIApplicationStateBackground || state == UIApplicationStateInactive)。做一些工作可能可以满足所有不同的情况。 - sam_smith
如果我按下主页按钮并发送通知,我看到了通知但选择点击应用程序图标而不是通知。那么我的应用程序将不会知道这个通知? - nr5

2
根据iOS 9.1的情况,我已经在Kill模式下测试了推送通知,此时我的应用程序没有在任何模式下运行。如果我点击推送通知,系统将首先调用。
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary *)userInfo{

//your code execution will here.

}

第二个方法调用将是:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//Your initial code execution.

}

我在我的应用程序中测试过这种情况。


你是如何测试这个场景的?请解释一下。 - Nico
Nico,我已经打印了Log到文档目录文件中检查,在推送通知的kill模式下将调用哪个方法。 - Gautam Sareriya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接