仅在设备正在充电和/或应用程序是前台时才会发送静音推送通知

时间:2014-11-16 16:49:35

标签: ios iphone background apple-push-notifications silent-notification

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

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

如果设备正在充电(即连接电缆)和/或我的应用程序是前台,则似乎只接收静音推送消息。

如果我断开设备与充电器(或Mac)的连接,则无法再接收静音推送通知,除非该应用是前台。

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

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

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

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

此行为在iPhone 5s,6和iPad 2上都是可重复的,所有这些都运行IOS 8或8.1。

还有其他人经历过这个吗?它应该很容易重现。为什么将设备插入充电器的简单行为会改变接收静音推送通知的能力?

8 个答案:

答案 0 :(得分:60)

我们遇到过相同的行为,并且一直试图了解为什么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分钟唤醒应用程序的程度。因此似乎存在某种衰减/限制公式,但我们找不到任何关于它如何正常工作的文档。我们已经请求此公式和apple中的变量作为支持请求,但是他们说“您要求的信息不公开”,并再次要求我们提交错误报告。

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

答案 1 :(得分:9)

随着iOS8背景推送到应用程序已发生变化。现在,只有在某些情况下才会将后台推送到应用程序。 Apple没有明确说明这些情况究竟是什么,但是从我的广泛实验来看,它基本上归结为手机是否正在充电。还有一些其他变量在起作用(例如网络类型,设备类型,启用wifi),但主要的主要因素是推送到达时设备是否正在充电。

如果手机通过直接主电源充电或通过USB连接到计算机间接充电,那么背景推送将在绝大多数时间内传送到应用程序。但是,断开手机与电源或USB的连接,即使手机的电池100%充电,也几乎不会将背景推送到应用程序。

你可以很容易地为自己测试这个,只需在手机正在充电时发送一些推送而不是手机充电。但是你必须考虑到后台推动开发构建和使用沙箱环境不要与生产构建和生产环境的后台推送相同,后台推送实际上更有可能在开发中传递给应用程序然后他们开始投入生产,因此使用生产版本和Apple的生产环境进行测试以查看实际结果至关重要。

注意推送传递有两个步骤,第一步是它需要传送到手机本身,第二步是手机拥有它,然后需要由操作系统传送到应用程序。在iOS7中,诸如Tifi on Wifi之类的东西使推动电话增加的机会增加了。使用iOS8,即使推送成功传送到手机,如果手机没有充电,操作系统也不会将其转发到后台应用程序。这意味着手机会收到通知并保留通知,有时持续几个小时,如果手机没有收费,它可能会转发给应用。

答案 2 :(得分:7)

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

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

此链接可能有用。 Apple Documentation

答案 3 :(得分:5)

我也注意到了同样的事情并浪费了一些时间来搞清楚。见https://stackoverflow.com/a/31237889/1724763

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

但是,我的观察是,如果您通过电缆连接到Xcode,那么Bg App Refresh设置将被忽略,并且您的应用程序的所有静音推送都可以正常工作。

我非常怀疑这是一个没有记录的功能:充电导致Bg App Refresh设置被忽略。

答案 4 :(得分:2)

由于您在plist中启用了错误的背景模式,因此无效。您需要启用remote-notification标记(应用下载内容以响应推送通知),而不是提取。 Fetch用于其他东西。您可能还需要使用JSON有效内容中的内容可用密钥,例如

{
   "aps": {
      "content-available": 1
    },
    "yourdatakey":{data}
}

答案 5 :(得分:1)

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

答案 6 :(得分: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 [注意,它看起来只有{{1}此时10是正确的值]),但由于我想要无声通知,我没有5alert或{ {1}}设置。

答案 7 :(得分:0)

我找到了另一个使用PushKit Framework

为我工作的解决方案

VoIP推送在VoIP应用程序所需的标准推送之上提供额外功能,以便在向用户显示通知之前执行推送的按需处理

当我发送VOIP推送时,应用程序会唤醒应用程序的任何状态并执行任何操作

在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服务证书的证书

enter image description here