ios 静默推送通知仅在设备正在充电和/或应用程序处于前台时传送
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26959472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Silent push notifications only delivered if device is charging and/or app is foreground
提问by user1024447
I have implemented silent push notifications but I have noticed some strange behaviour. The silent push notifications are handled via:
我已经实现了静默推送通知,但我注意到了一些奇怪的行为。静默推送通知通过以下方式处理:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
The silent push messages only seem to be received if the device is charging (ie cable connected) and/or if my app is foreground.
只有在设备正在充电(即连接电缆)和/或我的应用程序处于前台时,才会收到无声推送消息。
If I disconnect the device from the charger (or Mac) then the silent push notifications are no longer received unlessthe app is foreground.
如果我断开设备与充电器(或 Mac)的连接,则除非应用程序处于前台,否则不再收到静默推送通知。
I get non-silent push notifications normally in both cases.
在这两种情况下,我通常都会收到非静默推送通知。
If I plug in the USB cable again, then I get the expected behaviour and silent push notifications are received irrespective of whether the app is foreground or background.
如果我再次插入 USB 电缆,那么我会得到预期的行为,并且无论应用程序是前台还是后台,都会收到静默推送通知。
I am using UILocalNotification so I know what is being received.
我正在使用 UILocalNotification 所以我知道收到了什么。
The fact that it all works fine with the device connected suggests that my silent pushes notifications are configured correctly and that the app has the correct background modes set in the plist etc.
在连接的设备上一切正常的事实表明,我的静默推送通知配置正确,并且应用程序在 plist 等中设置了正确的后台模式。
This behaviour is repeatable on iPhone 5s, 6 and iPad 2 all running either IOS 8 or 8.1.
这种行为在运行 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?
有没有其他人经历过这种情况?应该很容易重现。为什么将设备插入充电器的简单操作会改变接收静默推送通知的能力?
回答by Kevin D.
We have experienced the same behavior and have been trying to understand why iOS decides to deliver some notifications and not others.
我们经历过同样的行为,并一直试图理解为什么 iOS 决定传递一些通知而不是其他。
What we have worked out so far is:
到目前为止,我们已经制定了:
Messages will get received more reliably in background when on wifi than on cellular data. In fact, when on a cellular network (3g/4g), if your signal strength isn't strong enough, iOS receives the push message, but will not wake up your app. We posted in the apple forums about it here: https://devforums.apple.com/message/1069814#1069814. We also opened up a support ticket, and the support team told us to lodge it as a bug report, which we did a couple of weeks ago and are still waiting to hear back.
When you receive a push message, you need to call the fetchCompletionHandler as soon as possible. Technically you have 30 seconds to perform background processing, but iOS has in place a formula whereby the more frequently you send push messages and depending on the amount of time you spend processing those message before returning the app to suspended state, iOS can reduce the amount of times your app gets woken up in the future.
在 wifi 上比在蜂窝数据上时,在后台接收消息会更可靠。实际上,在蜂窝网络(3g/4g)上,如果您的信号强度不够强,iOS 会收到推送消息,但不会唤醒您的应用。我们在苹果论坛上发布了关于它的信息:https: //devforums.apple.com/message/1069814#1069814。我们还开了一张支持票,支持团队告诉我们将其作为错误报告提交,我们几周前就做了,现在仍在等待回音。
当您收到推送消息时,您需要尽快调用 fetchCompletionHandler。从技术上讲,您有 30 秒的时间来执行后台处理,但 iOS 有一个公式,您发送推送消息的频率越高,根据您在将应用程序返回到挂起状态之前处理这些消息所花费的时间,iOS 可以减少数量您的应用程序在未来被唤醒的次数。
See here from Apple didReceiveRemoteNotification:fetchCompletionHandler:documentation:
从Apple didReceiveRemoteNotification:fetchCompletionHandler看这里:文档:
As soon as you finish processing the notification, you must call the block in the handler parameter or your app will be terminated. Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block. In practice, you should call the handler block as soon as you are done processing the notification. The system tracks the elapsed time, power usage, and data costs for your app's background downloads. Apps that use significant amounts of power when processing push notifications may not always be woken up early to process future notifications.
处理完通知后,您必须立即调用 handler 参数中的块,否则您的应用程序将被终止。您的应用程序有长达 30 秒的挂钟时间来处理通知并调用指定的完成处理程序块。实际上,您应该在处理完通知后立即调用处理程序块。系统会跟踪应用程序后台下载的运行时间、用电量和数据成本。在处理推送通知时使用大量电量的应用程序可能并不总是被提前唤醒以处理未来的通知。
In our testing, we have been sending frequent silent push notifications to our app (every 10 - 30 seconds). And the app is awake for about 3 seconds before we put it back to sleep. We have definitely noticed over time a degradation in the frequency in which our app gets woken up to the point where iOS will only wake up the app every 15 - 30 minutes. So there seems to be some sort of decay/throttling formula in place, but we cannot find any documentation on how it exactly works. We have requested this formula and the variables from apple as a support request, but they said "The information you are requesting is not publicly available" and again asked us to file a bug report.
在我们的测试中,我们一直在向我们的应用程序发送频繁的静默推送通知(每 10 到 30 秒)。在我们将其重新休眠之前,该应用程序会唤醒大约 3 秒钟。随着时间的推移,我们肯定注意到我们的应用程序被唤醒的频率下降到 iOS 只会每 15 到 30 分钟唤醒应用程序的程度。因此,似乎存在某种衰减/节流公式,但我们找不到任何关于它究竟如何工作的文档。我们已经向 Apple 请求了这个公式和变量作为支持请求,但他们说“您请求的信息不是公开可用的”,并再次要求我们提交错误报告。
So, hopefully this is helpful? We are still trying to learn more ourselves which is why I found this question :)
那么,希望这有帮助吗?我们仍在努力学习更多自己,这就是我发现这个问题的原因:)
回答by Gruntcakes
With iOS8 background push delivery to apps has changed. A background push will now only be delivered to the app under certain circumstances. Apple have not stated explicitly what these circumstances exactly are but from my extensive experimentation it basically comes down to if the phone is being charged or not. There are some other variables at play (such as network type, device type, wifi enabled) but the major major major factor is whether the device is being charged or not when the push arrives.
随着 iOS8 后台推送到应用程序的交付发生了变化。后台推送现在只会在某些情况下传送到应用程序。Apple 没有明确说明这些情况到底是什么,但根据我的广泛实验,它基本上可以归结为手机是否正在充电。还有一些其他变量在起作用(例如网络类型、设备类型、启用 wifi),但主要的主要因素是推送到达时设备是否正在充电。
If the phone is being charged via a direct mains power supply or indirectly by being connected by USB to a computer then the background pushes will get delivered to the app the vast majority of the time. But disconnect the phone from the power supply or USB and the background push will almost never get delivered to the app, even if the phone's batter has a 100% charge.
如果手机通过直接主电源充电或通过 USB 间接连接到计算机,则后台推送将在绝大多数时间发送到应用程序。但是断开手机与电源或 USB 的连接,即使手机的电池电量为 100%,后台推送也几乎永远不会传送到应用程序。
You can very easily test this for yourself just by sending some pushes while the phone is being charged versus while its not. BUT you must take into account that background pushes with a development build and using the sandbox environment DO NOT behave the same as background pushes with a production build and a production environment, the background pushes are actually more likely to be delivered to the app in development then they are in production so it is vital you test using a production build and Apple's production environment to see the actual results.
您可以非常轻松地自己测试,只需在手机正在充电时发送一些推送,而不是在不充电时发送一些推送。但是您必须考虑到使用开发构建和使用沙箱环境的后台推送与使用生产构建和生产环境的后台推送的行为不同,后台推送实际上更有可能交付给开发中的应用程序那么它们就在生产中,因此使用生产版本和 Apple 的生产环境进行测试以查看实际结果至关重要。
Note there are two steps the push delivery, the first is it needs to get delivered to the phone itself, the second is once the phone has it, it then needs to get delivered by the OS to the app. In iOS7 things such as turing on Wifi made the chances of the push getting to the phone increase. With iOS8 however even though the push is successfully being delivered to the phone, the OS is not forwarding it on to a background app if the phone isn't being charged. This means the phone gets the notification and holds on to it, sometimes for several hours, before it might forward it to the app if the phone isn't being charged.
请注意,推送传递有两个步骤,第一是需要传递到手机本身,第二是一旦手机拥有它,它就需要由操作系统传递到应用程序。在 iOS7 中,诸如图灵 Wifi 之类的东西使得推送到手机的机会增加。然而,在 iOS8 中,即使推送成功发送到手机,如果手机没有充电,操作系统也不会将其转发到后台应用程序。这意味着手机会收到通知并保留它,有时会持续几个小时,然后如果手机没有充电,它可能会将其转发到应用程序。
回答by Manan Devani
I had experienced the same problem and the reason behind not receiving push notification while the app is not charging is that when the Low Power Mode is enabled from Settings > Battery
it disables background-fetch
feature for all applications.
我遇到了同样的问题,在应用程序未充电时未收到推送通知的原因是,当启用低功耗模式时,Settings > Battery
它会禁用background-fetch
所有应用程序的功能。
Which prevents device from receiving push notification.
这会阻止设备接收推送通知。
This link might be useful. Apple Documentation
此链接可能有用。 苹果文档
回答by Manan Devani
I also noticed the same and wasted some time figuring out. See https://stackoverflow.com/a/31237889/1724763
我也注意到了同样的情况,并浪费了一些时间来弄清楚。见https://stackoverflow.com/a/31237889/1724763
If you turned off Bg App Refresh, silent remote push will be dropped silently (the irony).
如果您关闭 Bg App Refresh,静默远程推送将被静默删除(具有讽刺意味)。
However, my observation is that if you connect to Xcode via cable, somehow the Bg App Refresh setting is ignored and all silent push for your app works.
但是,我的观察是,如果您通过电缆连接到 Xcode,不知何故 Bg App Refresh 设置会被忽略,并且您的应用程序的所有静默推送都有效。
I highly suspect this is an undocumented feature: charging causes the Bg App Refresh setting to be ignored.
我高度怀疑这是一个未记录的功能:充电会导致 Bg App Refresh 设置被忽略。
回答by Mohamed yaseen
I hope you are using APNSdelivering priority as "CONSERVE_POWER" (5)
, try to change it as "IMMEDIATE" (10)
我希望你使用APNS提供优先级作为"CONSERVE_POWER" (5)
,尝试将其更改为"IMMEDIATE" (10)
回答by jrlocke
It's not working because you have enabled the wrong background mode in the plist. You need to enable the remote-notification
tag (App downloads content in response to push notifications), not fetch. Fetch is used for something else. You may also need to use the content available key in your JSON payload, e.g.,
它不起作用,因为您在 plist 中启用了错误的背景模式。您需要启用remote-notification
标签(应用程序下载内容以响应推送通知),而不是获取。Fetch 用于其他用途。您可能还需要在 JSON 有效负载中使用内容可用密钥,例如,
{
"aps": {
"content-available": 1
},
"yourdatakey":{data}
}
回答by Michael
I've been experiencing this problem for some time, and am very grateful for this question and @Kevin D. sharing their understanding. I'm beginning to think that https://stackoverflow.com/a/30834566/1449799and https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW4(see priority
in one of the tables) are describing why my app is having trouble:
我遇到这个问题已经有一段时间了,非常感谢这个问题和@Kevin D. 分享他们的理解。我开始认为https://stackoverflow.com/a/30834566/1449799和https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#/ /apple_ref/doc/uid/TP40008194-CH101-SW4(参见priority
其中一张表)描述了我的应用程序出现问题的原因:
It is an error to use this priority for a push that contains only the
content-available
key.
将此优先级用于仅包含
content-available
密钥的推送是错误的。
To send the notifications, I'm using node-apnwhere the default (which i also need) is to set the priority to max (10
[beware, it looks like only 10
and 5
are correct values at this time]), but since i wanted a silentnotification, i don't have alert
, badge
, or sound
set.
要发送通知,我正在使用node-apn,其中默认值(我也需要)是将优先级设置为 max(10
[注意,此时它看起来只是10
并且5
是正确的值]),但是因为我想要一个无声的通知,我没有alert
,badge
或sound
集。
回答by khaled
IF YOUR APP IS NOT VoIP YOU CAN'T FOLLOW THIS ANSWER [your app will be rejected]
如果您的应用程序不是 VoIP,则您无法遵循此答案 [您的应用程序将被拒绝]
I found another solution that is worked for me using PushKit Framework
我找到了另一个使用PushKit 框架对我有用的解决方案
VoIP pushes provide additional functionality on top of the standard push that is needed to VoIP apps to perform on-demand processing of the push before displaying a notification to the user
VoIP 推送在标准推送之上提供附加功能,VoIP 应用程序需要在向用户显示通知之前执行推送的按需处理
When I send VOIP Push the App wakes up whatever the state of the Application and can perform any operations
当我发送 VOIP Push 时,无论应用程序处于何种状态,应用程序都会唤醒并可以执行任何操作
Register for VOIP PushNotification in didFinishLaunchingWithOptions
在 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);}
then you can handle any background fetch in this function once you receive VOIP PushNotification
然后您可以在收到 VOIP PushNotification 后处理此功能中的任何后台提取
-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
NOTE: you must use certificate that enable VoIP Services Certificate
注意:您必须使用启用 VoIP 服务证书的证书