繁体   English   中英

静默推送通知仅在设备正在充电和/或应用程序处于前台时传送

[英]Silent push notifications only delivered if device is charging and/or app is foreground

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

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

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

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

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

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

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

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

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

有没有其他人经历过这种情况? 应该很容易重现。 为什么将设备插入充电器的简单操作会改变接收静默推送通知的能力?

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

到目前为止,我们已经制定了:

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

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

Apple didReceiveRemoteNotification:fetchCompletionHandler看这里文档:

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

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

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

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

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

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

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

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

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

此链接可能有用。 苹果文档

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

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

但是,我的观察是,如果您通过电缆连接到 Xcode,不知何故 Bg App Refresh 设置会被忽略,并且您的应用程序的所有静默推送都有效。

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

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

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

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

我遇到这个问题已经有一段时间了,非常感谢这个问题和@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 [注意,此时看起来只有105是正确值]),但是因为我想要一个无声通知,所以我没有设置alertbadgesound

如果您的应用程序不是 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 服务证书的证书

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM