推送通知触发后台刷新并显示推送通知 VS 静默推送。

24

我想在我的应用程序中实现后台刷新功能,以便在接收到推送通知时执行。在将推送通知显示给用户之前,我想从后端(Parse.com)下载新消息并将它们保存到一个数组中。我正在遵循这里的指南:http://developer.xamarin.com/guides/ios/application_fundamentals/backgrounding/part_3_ios_backgrounding_techniques/updating_an_application_in_the_background/

我不确定这个指南的准确性。它说:iOS 7(及更高版本)通过在向用户发出通知之前给应用程序一个机会来在后台更新内容,从而扩展了普通的推送通知,以便用户可以立即打开应用程序并呈现新内容。

因此,我尝试像这样实现我的后台推送:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
{


    if([[userInfo objectForKey:@"aps"] objectForKey:@"content-available"]){

        NSLog(@"Doing the background refresh");
        UINavigationController *navigationController=(UINavigationController *)[[[UIApplication sharedApplication] keyWindow] rootViewController];

        MyViewController *myViewController = (MyViewController *)[[navigationController viewControllers] objectAtIndex:1];

        [myViewController.currentUser refreshMessagesArrayWithCompletionHandler:^(BOOL successful, BOOL newMiaos) {

            NSLog(@"messages refreshed the array now has %lu messages",(unsigned long)[myViewController.currentUser.messages count]);
            handler(UIBackgroundFetchResultNewData);
        }];
    }
}

后台刷新被调用并显示推送通知,但是该推送通知并不等待后台任务完成就立即被显示。这是正常的功能吗?上面的教程表明,直到后台任务完成之前,通知才会被显示。

然后我尝试了一种“静默通知”,当接收到推送时,它会触发应用在后台下载消息,但不显示通知。因此,在下载完成后,我通过触发本地通知来实现这一点。这真的是正确的做法吗?传统的应用程序(如WhatsApp)是否使用静默通知触发后台刷新,然后触发本地通知?似乎有点hacky。毕竟,后台推送的想法是在显示通知之前准备好数据,但事实并非如此。

我注意到另一件事是,静默通知受到限制,它们的优先级低于典型推送通知,因此这显然也会影响应用程序的效率...

如果您对此有任何指导,真的会很感激。只是试图理解我是否以正确的方式处理此问题。所有这些都似乎非常hacky...


我已经尝试过这个方法,但是当应用程序在后台时,didReceiveRemoteNotification:并没有从推送通知中打开。你知道为什么吗?当我们想要接收推送通知并在应用程序在后台时调用一些程序时,应该使用哪种方法?我能够收到通知消息,但是除非我们按下并打开应用程序,否则无法进入该过程。还有其他的方法来完成这个过程吗? - Moxarth
2个回答

19

我在我的消息应用中遇到了同样的问题。我们希望用户在点击通知之前能够看到消息。

  • 负载大小限制。iOS 7 的负载仅有256字节。
  • 单个静默通知如果应用程序没有运行,将不会启动应用程序。
  • content-available 通知如果没有警报正文,甚至可能无法传递到设备上。
  • 后台抓取不受您的应用程序控制,因此您可能永远无法接收所需信号,因此我们不能依赖此功能。但这可能是实现我们想要的额外途径。
  • iOS 8 有很大的负载空间-2KB。
  • 如果您发送警报正文 content-available - 在大多数情况下,它将被传递,并且应用程序能够处理它。

因此,我们得出唯一可接受的解决方案:我们决定仅在ios8+上提供此功能。我们发送带有content-available键的可见推送通知,如果进程正在运行/冻结,则允许我们处理通知负载,并且如果应用程序未运行,则可以呈现通知。如果应用程序收到推送通知,它会将警报文本正文写入本地数据库,因此用户可以在对话中阅读它。根据我们的统计数据,消息的平均大小不超过200个字符,因此大多数时间不需要额外的请求。如果消息超过200个字符,我们将扩展负载正文并使用额外参数请求推送通知处理中的文本正文。用户将看到裁剪版本的文本,但是在完成请求后,我们将使用接收到的值重新编写本地数据库中的消息。

因此,这种技术允许我们在大多数情况下立即向用户显示接收到的消息,如果应用程序未运行,则在应用程序启动后立即向我们的服务器发出请求以获取缺失的消息。这是我们在iOS上能够得到的最快速和最可接受的情况。希望我的经验能帮助您实现您想要的功能。


嘿,感谢这个。只想问几件事情。您说没有警报正文的静默通知甚至可能不会传递到设备上。没有警报正文的静默通知就是静默通知,对吗?从苹果的文档中,似乎静默和标准通知具有相同的优先级。 - Kex
不会。当通知发生时,您的应用程序将立即接收到该信号。无论用户有多快,处理器都更快=)如果您将警报正文直接写入数据库,则用户在点击通知后立即会看到它。在极少数情况下(当消息长度超过200个符号时。您可以选择不同的长度,2 KB的有效负载是很大的空间),用户可能会在短时间内看到被裁剪的文本版本,然后将其替换为服务器答案。我的统计数据显示,即使在边缘网络上,短的http请求速度也足够快。 - Sega-Zero
我已经尝试过这个方法,但是当应用程序在后台时,didReceiveRemoteNotification:并没有从推送通知中打开。你知道为什么吗?当我们想要接收推送通知并在应用程序在后台时调用一些程序时,应该使用哪种方法?我能够收到通知消息,但是除非我们按下并打开应用程序,否则无法进入该过程。还有其他的方法来完成这个过程吗? - Moxarth
是的,我也尝试过了。但仍然如此。我收到通知消息,但在用户点击通知之前无法进入方法application:didReceiveRemoteNotification:fetchCompletionHandler。 - Moxarth
只有在这之后,我才会收到通知。 - Moxarth
显示剩余11条评论

9
你把几件事情混在了一起。
从你的链接快速查看,这是一个关于xamarin的指南。可能有一些正确的信息,但如果你不使用xamarin,我建议你寻找另一个教程。
一个好的方法是向用户发送一个静默通知,并在完成后触发本地通知(这并不算是hacky)。
这就是whatsApp如何使其工作的:
当whatsApp处于后台时,会收到一个单独的推送通知(例如“5”),该消息不会显示给用户。
whatsApp在方法application:didReceiveRemoteNotification:fetchCompletionHandler:中接收到它,并检查他们的服务器是否有任何用户没有收到的“5”之前的通知。如果是这样,他们将从他们的服务器中提取该数据,并使用本地通知向用户呈现它,这基本上只是一种呈现数据的方式,与APNS无关。
你可以在我写的另一个答案这里阅读完整的回答和上下文。

1
静默通知的优先级比标准APNS低吗?我知道标准APNS是“最大努力”,但我担心静默通知的优先级甚至比这个更低,可能无法传递。 - Kex
根据苹果公司的说法,所有通知的发送都是“尽力而为”的。我不知道通知类型之间是否有优先级区分。 - Segev
1
是的,我也读到了这个。我认为这是Xamarin文档让事情变得混乱了。使用静默通知需要应用程序具有后台模式权限,这是正确的吗?这是否意味着如果用户禁用它,所有通知都将完全无用?例如,对于静默通知,alert = "",因此不会显示任何消息,因为我们无法在没有后台模式的情况下引用服务器上的任何内容,因此没有推送内容可供使用。 - Kex
以下是有关此问题的好教程:http://www.g8production.com/post/70884102379/ios7-multitasking-the-background-fetch - Segev
谢谢。我看到有两种方法,一种用于处理标准推送,另一种用于静默推送。但是,如果您发送了一个静默推送并且禁用了后台模式,那么当content-set=1时,AppDelegate.m会将其解释为静默通知,但无法执行任何操作,因为后台模式已关闭。或者它会调用-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo吗? - Kex
1
为了能够处理静默推送通知,您需要将 application:didReceiveRemoteNotification:fetchCompletionHandler:remote-notification 关键字添加到 UIBackgroundModes 中。您可以设置优先级,但如果使用 pase.com,则会降低静默通知的优先级。 - Sega-Zero

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