57

我已经实现了静默推送通知,但我注意到了一些奇怪的行为。静默推送通知通过以下方式处理:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

只有在设备正在充电(即连接电缆)和/或如果我的应用程序在前台时,才会收到无声推送消息。

如果我断开设备与充电器(或 Mac)的连接,则不会再收到静默推送通知,除非应用程序在前台。

在这两种情况下,我通常都会收到非静音推送通知。

如果我再次插入 USB 电缆,那么无论应用程序是前台还是后台,我都会收到预期的行为并收到静默推送通知。

我正在使用 UILocalNotification 所以我知道收到了什么。

在连接的设备上一切正常的事实表明我的静默推送通知配置正确,并且应用程序在 plist 等中设置了正确的背景模式。

这种行为在运行 IOS 8 或 8.1 的 iPhone 5s、6 和 iPad 2 上是可重复的。

Has anyone else experienced this? It should be easy to reproduce. Why should the simple act of plugging a device into a charger change the ability to receive silent push notifications?

4

8 回答 8

65

我们经历过同样的行为,并且一直在试图理解为什么 iOS 决定发送一些通知而不是其他通知。

到目前为止,我们已经解决的是:

  • 使用 wifi 时,在后台接收消息比使用蜂窝数据更可靠。事实上,在蜂窝网络(3g/4g)上,如果您的信号强度不够强,iOS 会收到推送消息,但不会唤醒您的应用程序。我们在苹果论坛上发布了关于它的信息:https ://devforums.apple.com/message/1069814#1069814 。我们还开出了一张支持票,支持团队告诉我们将其作为错误报告提交,我们几周前就这样做了,现在仍在等待回复。

  • 当您收到推送消息时,您需要尽快调用 fetchCompletionHandler。从技术上讲,您有 30 秒的时间来执行后台处理,但 iOS 有一个公式,您发送推送消息的频率越高,根据您在将应用程序返回到挂起状态之前处理这些消息所花费的时间,iOS 可以减少数量您的应用在未来被唤醒的次数。

参见Apple didReceiveRemoteNotification:fetchCompletionHandler:文档:

处理完通知后,您必须在处理程序参数中调用该块,否则您的应用程序将被终止。您的应用程序有最多 30 秒的挂钟时间来处理通知并调用指定的完成处理程序块。在实践中,您应该在处理完通知后立即调用处理程序块。系统会跟踪应用后台下载的经过时间、用电量和数据成本。在处理推送通知时使用大量电力的应用程序可能并不总是被提早唤醒以处理未来的通知。

在我们的测试中,我们一直在向我们的应用程序发送频繁的静默推送通知(每 10 - 30 秒)。在我们让它重新进入睡眠状态之前,该应用程序会唤醒大约 3 秒钟。随着时间的推移,我们肯定注意到我们的应用程序被唤醒的频率下降到 iOS 只会每 15 到 30 分钟唤醒应用程序的程度。所以似乎有某种衰减/节流公式,但我们找不到任何关于它如何工作的文档。我们已向苹果请求此公式和变量作为支持请求,但他们说“您请求的信息不公开”并再次要求我们提交错误报告。

那么,希望这有帮助吗?我们仍在努力自己了解更多,这就是我发现这个问题的原因:)

于 2014-11-19T03:49:22.343 回答
9

随着 iOS8 应用程序的后台推送交付发生了变化。后台推送现在只会在某些情况下传送到应用程序。苹果没有明确说明这些情况到底是什么,但根据我的大量实验,它基本上可以归结为手机是否正在充电。还有一些其他变量在起作用(例如网络类型、设备类型、启用 wifi),但主要的主要因素是推送到达时设备是否正在充电。

如果手机是通过直接电源或通过 USB 连接到计算机间接充电,那么后台推送将在绝大多数时间传递到应用程序。但是断开手机与电源或 USB 的连接,后台推送几乎永远不会发送到应用程序,即使手机的电池电量为 100%。

您可以很容易地自己测试这一点,只需在手机充电时发送一些推送,而不是在不充电时发送。但是您必须考虑到,使用开发构建和使用沙盒环境的后台推送与使用生产构建和生产环境的后台推送的行为不同,后台推送实际上更有可能交付给开发中的应用程序然后它们在生产中,因此使用生产构建和 Apple 的生产环境进行测试以查看实际结果至关重要。

注意推送有两个步骤,第一个是需要自己发送到手机上,第二个是手机有后,然后需要由操作系统发送到应用程序。在 iOS7 中,开启 Wifi 等功能使得推送到手机的机会增加。然而,对于 iOS8,即使推送已成功发送到手机,如果手机未充电,操作系统也不会将其转发到后台应用程序。这意味着手机会收到通知并保持它,有时会持续几个小时,然后如果手机没有被充电,它可能会将其转发到应用程序。

于 2015-03-31T17:02:15.803 回答
9

我遇到了同样的问题,而应用程序未充电时未收到推送通知的原因是,当启用低功耗模式时,Settings > Battery它会禁用background-fetch所有应用程序的功能。

这会阻止设备接收推送通知。

这个链接可能有用。 苹果文档

于 2016-11-29T12:48:13.940 回答
6

我也注意到了这一点,并浪费了一些时间来弄清楚。见https://stackoverflow.com/a/31237889/1724763

如果您关闭了 Bg App Refresh,静默远程推送将被静默丢弃(具有讽刺意味)。

但是,我的观察是,如果您通过电缆连接到 Xcode,Bg App Refresh 设置会以某种方式被忽略,并且您的应用程序的所有静默推送都会起作用。

我高度怀疑这是一个未记录的功能:充电会导致 Bg App Refresh 设置被忽略。

于 2015-10-25T08:18:54.033 回答
2

它不起作用,因为您在 plist 中启用了错误的背景模式。您需要启用remote-notification标签(应用程序下载内容以响应推送通知),而不是获取。Fetch 用于其他用途。您可能还需要在 JSON 有效负载中使用内容可用密钥,例如,

{
   "aps": {
      "content-available": 1
    },
    "yourdatakey":{data}
}
于 2014-11-25T22:51:05.190 回答
2

我希望您使用APNS提供优先级"CONSERVE_POWER" (5),尝试将其更改为"IMMEDIATE" (10)

于 2017-06-08T06:58:18.597 回答
0

如果您的应用不是 VoIP,您将无法遵循此答案 [您的应用将被拒绝]

我找到了另一个使用PushKit 框架对我有用的解决方案

VoIP 推送在标准推送之上提供附加功能,VoIP 应用程序需要在向用户显示通知之前执行推送的按需处理

当我发送 VOIP Push 时,无论应用程序的状态如何,应用程序都会唤醒并可以执行任何操作

在 didFinishLaunchingWithOptions 中注册 VOIP PushNotification

 PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];


- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
    NSLog(@"voip token NULL");
    return;
}

NSString *originalToken=[NSString stringWithFormat:@"%@",credentials.token];
NSString *token = [originalToken stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"<>"]];
token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"PushCredentials: %@",token);}

然后您可以在收到 VOIP PushNotification 后处理此函数中的任何后台获取

-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type

注意:您必须使用启用 VoIP 服务证书的证书

在此处输入图像描述

于 2016-01-04T11:58:13.027 回答
0

我遇到这个问题已经有一段时间了,非常感谢这个问题和@Kevin D. 分享他们的理解。我开始认为https://stackoverflow.com/a/30834566/1449799https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#/ /apple_ref/doc/uid/TP40008194-CH101-SW4(参见priority其中一张表)描述了我的应用程序出现问题的原因:

将此优先级用于仅包含content-available密钥的推送是错误的。

为了发送通知,我正在使用node-apn,其中默认值(我也需要)是将优先级设置为 max (10[注意,此时它看起来只是10并且5是正确的值]),但是因为我想要无声通知,我没有,alert ,badgesound设置。

于 2015-10-20T18:14:37.517 回答