应用程序:didReceiveRemoteNotification:fetchCompletionHandler未被调用

23
在应用程序被强制退出时似乎无法调用application:didReceiveRemoteNotification:fetchCompletionHandler函数。我原本以为无论应用程序处于什么状态,该函数都会被调用,但实际上只有在应用程序已经在后台运行时才会调用它。是否有一种方法可以使用新的iOS 7远程通知后台模式唤醒尚未运行的后台应用程序?

1
你可能需要检查设备的后台获取设置,前往“设置”->“通用”->“后台应用刷新”,确保已激活适当的设置。 - Yogurt
8个回答

52
即使应用程序被挂起、未运行、在后台或处于活动状态,application:didReceiveRemoteNotification:fetchCompletionHandler: 仍会被调用。值得注意的是该方法仅适用于iOS 7或以上版本。此处为苹果文档然而,如果应用程序被强制关闭(即通过应用程序切换器杀死),则应用程序将不会被启动。 (见 SO 答案编辑:我在 iOS 7.1 上再次进行了检查,看看他们是否修复了这个问题,但如果应用程序被手动关闭,则仍然存在这种情况,应用程序不会被唤醒,application:didReceiveRemoteNotification:fetchCompletionHandler: 不会被调用。
当接收到推送时,只有在需要调用 application:didReceiveRemoteNotification:fetchCompletionHandler: 方法时才会唤醒应用程序(即您必须在推送通知负载中设置 "content-available" 标志。参见 SO 答案)。如果用户通过点击通知打开应用程序,则该方法将被再次调用。 编辑: 我没有在 iOS 8 上检查过这个问题。还有其他人吗?

4
尽管似乎令人困惑,但当应用程序完全未运行时,会调用该方法,但如果应用程序已被强制关闭,则不会运行。这是另一种应用程序状态吗? - Yogurt
6
iOS认为强制关闭应用程序不是另一个应用程序状态,而是用户不希望该应用程序运行任何进程线程,直到下次启动。这符合苹果的意图,尽管他们的设计理念可能存在问题,如果不考虑人们实际使用应用程序切换器的情况,这种设计就显得非常反人类和愚蠢。 - Jeremy
@nvrtd,您所说的“仅限iOS 7”是指不包括iOS 8吗? - Van Du Tran
@VanDuTran 很好的观点。我还没有检查过。有人在iOS 8上检查过吗?我认为他们没有改变,但我不确定。 - nvrtd frst
1
我刚在iOS 8.4上发现了这个问题。 - reallyseth
1
application:didReceiveRemoteNotification:fetchCompletionHandler: 是 iOS 9 中所需的方法。 - Michael

25
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions {

    //Remote Notification Info
    NSDictionary * remoteNotifiInfo = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];

    //Accept push notification when app is not open
    if (remoteNotifiInfo) {
       [self application:application didReceiveRemoteNotification: remoteNotifiInfo];
    }

    return YES;
}

2
-1,它不会在强制退出下进行处理。 当用户通过点击通知按钮启动应用程序时,上述代码将运行。 - dimpiax
1
非常好的答案,这个答案应该被接受。 - Bhavesh Lathigara
这真的解决了问题!在 application:didReceiveRemoteNotification: 中,我们像往常一样收到了那个通知。 - Dmitry Isaev

3
当您的应用程序被强制退出时,该方法不会被调用。相反,通常会调用 (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法。
如果应用程序是通过点击通知弹出窗口中的“打开”而打开的,则通知位于 launchOptions 中。
按以下方式获取推送通知字典:
NSDictionary * pushNotificationUserInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

if (pushNotificationUserInfo)
{
  // call your handler here
}

3
即使应用程序未运行,也应该启动该应用程序。苹果的文档如下所示:
当此值存在且推送通知到达设备时,系统会将通知发送给您的应用程序(如果需要,将其启动)并在向用户显示任何内容之前给它一些时间来处理通知。 (iOS App编程指南)
当推送通知到达时,系统会将通知显示给用户并在需要时在后台启动应用程序,以便可以调用此方法。 (UIApplicationDelegate协议参考)
与仅在应用程序运行时调用的application:didReceiveRemoteNotification:方法不同,系统会在调用此方法之前,无论应用程序的状态如何,都调用此方法。如果您的应用程序处于挂起或未运行状态,则系统会唤醒或启动您的应用程序,并将其置于后台运行状态,然后再调用该方法。 (UIApplicationDelegate协议参考)
但是,使用“content-available”:1推送进行测试时,当应用程序未运行时,该应用程序从未被启动。当该应用程序处于挂起状态时,它可以正常工作。
Wes,你找到解决方案了吗?

@emiel:当我的应用程序被终止/挂起时,我需要你的帮助。现在我收到一个通知并在不打开应用程序的情况下向服务器发送数据。如何实现或调用哪个 UIApplicationDelegate 协议参考方法? - Bhadresh Sonani

2
根据苹果文档,新的多任务API(获取和远程通知)仅在应用程序处于挂起/后台/前台状态下工作。
  • 在后台/前台状态下,将触发application:didReceiveRemoteNotification:fetchCompletionHandler

  • 在挂起状态下,将触发-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

  • 在未运行状态(您的情况),application:didReceiveRemoteNotification:fetchCompletionHandler永远不会被触发。

有关应用程序状态的更多信息,请参考苹果文档

6
与应用程序的didReceiveRemoteNotification:方法不同,该方法无论您的应用程序是否运行,系统都会调用它。如果您的应用程序已暂停或未运行,系统会唤醒或启动您的应用程序,并在调用该方法之前将其置于后台运行状态。确定翻译正确无误吗? - lucaconlaq
如果应用程序处于“未运行”状态,则远程通知不会唤醒该应用程序。 - Nandha
2
我同意Luka的评论。答案是不正确的。无论应用程序是挂起、未运行或在后台运行,application:didReceiveRemoteNotification:fetchCompletionHandler:都会被调用。另外值得注意的是,上述方法仅适用于iOS 7。 - nvrtd frst
1
@Nandha 是的,我有。只是为了明确起见,这里被问及的方法是 application:didReceiveRemoteNotification:fetchCompletionHandler:,而不同于 application:didReceiveRemoteNotification:。这是[苹果文档](https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplicationDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler/)第一个方法。 - nvrtd frst
1
值得注意的是:当接收到推送时,仅在需要调用application:didReceiveRemoteNotification:fetchCompletionHandler:方法时才会唤醒应用程序。即,在推送通知负载中,您必须设置“content-available”标志(请参见[SO答案](https://dev59.com/f3jZa4cB1Zd3GeqPYwIh#19403462))。如果用户通过点击通知打开应用程序,则该方法将再次被调用。 - nvrtd frst

1

针对Swift 2.0的相关人员,我已经通过以下方式解决了我的问题,这是针对背景的。

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {

    pushNotificationAction(remoteNotification as [NSObject : AnyObject])
}

1
如果你从应用程序切换器中强制退出一个应用程序,它将不会在后台被唤醒(通过任何方式)直到下一次启动。当你强制退出一个应用程序时,实际上是告诉操作系统你不想让这个应用程序运行,即使一个后台事件通常会唤醒它。
在测试过程中要注意这一点,因为你可能已经强制退出了应用程序,以便检查当应用程序没有运行时是否通过推送通知启动。事实上,你使用强制退出的原因就是它无法启动。

0

我最近遇到了同样的问题,然后我发现苹果更新了他们的文档并说:

但是,如果用户强制退出应用程序,则系统不会自动启动您的应用程序。在这种情况下,用户必须重新启动您的应用程序或重新启动设备,然后系统才会再次尝试自动启动您的应用程序。

application(_:didReceiveRemoteNotification:fetchCompletionHandler:)

所以我猜当应用程序被强制退出时就没有办法做任何事情了吗?


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