iOS 11 上的静默推送未发送到应用程序
Posted
技术标签:
【中文标题】iOS 11 上的静默推送未发送到应用程序【英文标题】:Silent pushes not delivered to the app on iOS 11 【发布时间】:2017-06-28 07:51:26 【问题描述】:我注意到在 ios 11 beta 2 上,无论应用程序的状态(背景/前景)如何,静默通知都不会发送到 application:didReceiveRemoteNotification:fetchCompletionHandler
。
我实现了UIApplicationDelegete
方法application:didReceiveRemoteNotification:fetchCompletionHandler
并发送以下静默推送
"aps":
"content-available": 1
,
"mydata":
"foo": "bar"
但在 iOS 11 上不调用委托方法。
它在其他版本的 iOS 上运行良好,文档部分 Configuring a Silent Notification 没有提到应该做任何其他事情。
这是 iOS 11 中的错误还是我错过了 iOS 11 中的新内容?
请注意,我不是在谈论或使用 UserNotification
框架,发送静默推送不需要它。
这是说明问题的sample project(您必须设置自己的捆绑包 ID)
当您午餐示例项目并将上述负载发送到应用程序时,您可以使用 macOS 控制台查看推送是否正确传递到设备而不是应用程序。
更新 10.08
看起来这种行为是随机的。有时重启设备后,payload 会正确传递,但一段时间后会停止工作。
如下图所示,标记为 1 的推送仅发送到设备,推送 2(设备重启后)也发送到应用。
更新 14.08 - iOS 11 Beta 6
仍然是相同的行为。另一件应该有效但无效的事情是以下内容。当应用程序的方案设置为“等待可执行文件启动”时,静默推送应该唤醒应用程序并在后台启动它。
更新 21.08 - iOS 11 Beta 7
仍然是相同的行为,并且在错误报告中没有来自 Apple 的更新。
更新 29.08 - iOS 11 Beta 8
还是同样的问题。我现在使用的重现步骤如下:
在 Xcode 项目方案中,选择“等待可执行文件启动” 在didReceiveRemoteNotification: fetchCompletionHandler
中添加断点
在设备上启动应用程序
发送上面的静默推送
预期:应用从挂起状态进入后台并调用didReceiveRemoteNotification: fetchCompletionHandler
实际:什么都没发生
更新 06.09 - iOS 11 Beta 10
我仍然有同样的错误行为。 Apple 的票已更新为以下答案:
Apple Developer Relations 2017 年 9 月 6 日晚上 10:42 提供了有关此问题的以下反馈:
我们能够让示例应用运行并测试其行为。我们 当我们按照描述进行测试时,没有发现任何问题。
不能保证推送在运行时到达应用程序 背景,这里的日志表明我们不相信该应用程序是 被用来启动它。
我们确实看到我们不时在条件允许的情况下提供推送 好的。
我们认为这是正确的。
更新 11.09
我的 Apple 错误报告已关闭并标记为 33278611
的副本,该报告仍处于打开状态
更新 13.09 - iOS 11 GM
感谢 kam800 的 cmets(见下文),我进行了更多测试并得出了这些观察结果:
iOS 11 中似乎有一个新的守护进程dasd DuetActivitySchedulerDaemon
要么完全丢弃数据推送,要么延迟数据推送传递:
交货推迟
控制台日志
default 13:11:47.177547 +0200 dasd DuetActivitySchedulerDaemon CANCELED: com.apple.pushLaunch.net.tequilaapps.daylight:C03A65 <private>! lifecycle com.apple.duetactivityscheduler
default 13:11:47.178186 +0200 dasd DuetActivitySchedulerDaemon Removing a launch request for application <private> by activity <private> default com.apple.duetactivityscheduler
default 12:49:04.426256 +0200 dasd DuetActivitySchedulerDaemon Advancing start date for <private> by 6.5 minutes to Wed Sep 13 12:55:31 2017 default com.apple.duetactivityscheduler
default 13:21:40.593012 +0200 dasd DuetActivitySchedulerDaemon Activity <private>: Optimal Score 0.6144 at <private> (Valid Until: <private>) scoring com.apple.duetactivityscheduler
default 13:21:40.594528 +0200 dasd DuetActivitySchedulerDaemon Setting timer (isWaking=1, activityRequiresWaking=0) between <private> and <private> for <private> default com.apple.duetactivityscheduler
延迟交付问题
当数据推送延迟交付并启动应用程序时,只有在未来几分钟到达交付日期时才会交付数据推送。这完全违背了使用数据推送来保持新应用程序的内容为下一次发布做好准备的目的。我在这里再次引用 Apple 的文档:当向暂停的应用发送 两个 数据推送时,它们会被 iOS 11 推迟,而不是直接唤醒应用。当到达交付时间时,只交付最后一个数据推送!之前的推送丢失并且没有通过委托方法传递,从而导致数据丢失。“无声通知通过帮助您保持 你的应用程序是最新的,即使它没有运行。”
发货取消
控制台日志
default 13:35:05.347078 +0200 dasd DuetActivitySchedulerDaemon com.apple.pushLaunch.net.tequilaapps.daylight:C03A65:[
name: ApplicationPolicy, policyWeight: 50.000, response: Decision: Must Not Proceed, Score: 0.00
], FinalDecision: Must Not Proceed scoring com.apple.duetactivityscheduler
取消配送问题
在这种情况下,数据推送完全丢失并且从未在 iOS 11 上交付,而在 iOS 10 上正确交付。
更新 19.09 - iOS 11 GM
我还注意到,当应用程序处于前台并且通知未传递到应用程序时,我在控制台中看到以下日志:
default 08:28:49.354824 +0200 apsd apsd <private>: Received message for enabled topic '<private>' onInterface: NonCellular with payload '<private>' with priority 10 for device token: NO courier-oversized com.apple.apsd
fault 08:33:18.128209 +0200 dasd Foundation <NSXPCConnection: 0x151eee460> connection from pid 55: Exception caught during decoding of received message, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSNull'. Allowed classes are '(
NSArray,
NSData,
NSString,
NSNumber,
NSDictionary,
NSUUID,
_DASActivity,
NSSet,
_DASFileProtection,
NSDate,
NWParameters,
NWEndpoint
)'. general com.apple.foundation.xpc
【问题讨论】:
在 Beta 8 中仍未修复,当我查看控制台时,我看到以下错误:"content-available": 1
推送发送,并且应用程序处于前台,则不会触发回调。跨度>
在使用新的 iOS11.1 beta 1 进行测试后,现在似乎已修复此问题,并且在 iOS 10 上可以正常工作
Whatsapp 似乎也有类似的问题 whatsappen.com/news/5465/… 大多数开发人员“习惯性地强制关闭他们的应用程序”的用户...
和11.1的公开发布完全一样。如果您使用静默推送并且您的应用位于前台,则不要指望它们会根据几个因素交付,而主要取决于电池电量,即使设备已插入电源。
【参考方案1】:
iOS 11.1 beta 1 的发行说明这么说
iOS 11.1 beta 1 刚刚发布,他们提到: “通知 已解决的问题 • 更频繁地处理静默推送通知。 (33278611)
我做了一些测试,似乎确实修复了:
暂停状态
当我以挂起模式启动应用并发送静默推送时,应用将返回后台并调用 didReceiveRemoteNotification:fetchCompletionHandler
委托。
前台状态
同样,当应用程序处于前台并发送静默推送时,委托似乎按预期调用。这在以前的 iOS 11 版本中随机不工作,所以我会在更多测试后确认这一点。
【讨论】:
在我最初的测试中,我认为它已修复。它工作了一段时间。但是经过一些严格的测试后,事情开始有所下降。突然间,即使应用程序在前台,它也停止在每次静默推送时调用代理。显然,由于缺少“energyBudget”,这个新的“二重唱”系统正在阻止我的应用程序的委托被调用。所以,不幸的是,仍然没有修复。 难以置信:( 我的经历和上面的Abras一样。工作了一段时间然后分崩离析,不再调用处理程序 - 这很糟糕, 经过更多测试,我找到了让设备再次接收通知的方法。将其连接到电源。一旦您将设备连接到电源,它将再次开始接收所有远程通知。如果断开它,它就会停止。这是没有意义的,因为在我所有的测试中,应用程序都在前台。并且保证前台应用程序可以接收远程通知。 对我来说,即使在没有连接电源的情况下使用蜂窝连接,它也能正常工作。只有当我将设备设置为省电模式时,即使在前台我也不会收到推送。但这是我能理解的【参考方案2】:只是想在此处添加我的 2 美分,因为我也遇到了这个问题,我注意到苹果已经关闭了几个关于这个问题的雷达,说它们无法重现。我发现一个有趣的事情是,如果应用程序在附加到调试器时处于后台,则推送将被传递。
如果我终止调试器,拔下手机,启动应用程序,然后发送静默推送有效负载,我会看到应用程序没有被唤醒。我确实在控制台日志中看到系统取消了将有效负载传送到我的应用程序。
我提交了一个雷达,其中包含一个可以重现问题的小型示例应用。我还在雷达中明确指出,处理我的票证的人不得运行附加到调试器的应用程序来重现问题。这是链接:https://bugreport.apple.com/web/?problemID=34461063
希望这会在这个问题上取得一些进展。
【讨论】:
感谢您的报告。顺便说一句,链接 Apple 错误在这里无济于事,因为它们是私密的,只有记者和 Apple 才能看到它们 我希望看到更多人使用openradar.appspot.com,以便我们可以跟踪其他人的雷达 苹果@bill 对您的错误报告有任何更新 我没有从 Apple 那里得到任何更新,但我们已经安装了 iOS 11.1 的测试版,而且问题似乎已经解决。 是的,我们在 iOS 11.2.6 中也面临同样的问题,有什么解决方案或更新吗?【参考方案3】:看起来像是 iOS 11 的新行为。iOS 11 beta 10 提供了一些关于此问题的描述性日志:
default 23:18:51.806011 +0200 dasd com.apple.pushLaunch.com.acme.Acme:F7E7D0:[
name: ApplicationPolicy, policyWeight: 50.000, response: Decision: Can Proceed, Score: 0.50
name: BatteryLevelPolicy, policyWeight: 1.000, response: Decision: Can Proceed, Score: 0.87, Rationale: [batteryLevel == 62]
name: DeviceActivityPolicy, policyWeight: 5.000, response: Decision: Can Proceed, Score: 0.20
] sumScores:52.279483, denominator:81.410000, FinalDecision: Can Proceed FinalScore: 0.642175
default 23:18:51.806386 +0200 dasd 'com.apple.pushLaunch.com.acme.Acme:F7E7D0' has compatibility score of 1.000000 with 'com.apple.CFNetwork-cc-111-79:E7272D'. Relaxing scores.
default 23:18:51.806855 +0200 dasd 'com.apple.pushLaunch.com.acme.Acme:F7E7D0' CurrentScore: 0.642175, ThresholdScore: 0.738454 DecisionToRun:0
看起来每个静默推送都传递到 iOS,但 dasd 守护进程使用几个策略来决定是否应将静默推送传递到应用程序(例如电池电量)。昨天晚上我设法收到了一次无声推送,但当时我的 iPhone 已连接到充电器 - 可能 BatteryLevelPolicy 分数高到足以接收到那次无声推送。
Apple 没有提供有关此 iOS 端行为的官方信息,仅提供有关服务器端限制的信息:
静默通知并不意味着让您的应用保持清醒状态 背景,也不是为了高优先级更新。 APNs 将静默通知视为低优先级,并可能限制其 如果总数变得过多,则完全交付。实际上 限制是动态的,可以根据条件改变,但尽量不要 每小时发送多个通知。
我很高兴,他们改变了这种行为,因为这会修复我的应用 :) 另一方面,这种改变是好的——其中之一是使 iPhone 电池的续航时间比 android 手机更长。
【讨论】:
是的,推送被传递到设备而不是应用程序。这就是我在原帖中写的。 “静默通知并不意味着让您的应用程序在后台保持清醒”,只要它们“有时”发送就可以了。最大的问题是,在 iOS 11 中,静默通知从不在后台发送到应用程序。这完全违背了数据推送的全部目的。 是的,你已经写过了,我只是想对这些新的推送策略提供完整的解释。我引用了 Apple 文档来表明他们已经警告过推送交付的不确定性。正如我所写:“昨天晚上我设法收到了一个无声的推送”(在我的意思的应用程序中),并且该应用程序在后台。但是在那天——我的应用程序没有收到推送:(在我看来,Apple 会在 RC 版本中放宽这些推送策略。另一方面,他们可以恢复原始推送行为——他们已经习惯于摆脱仅在测试版(例如 10.3 钥匙串自动删除)。 收到推送并且应用暂停时,我看到了类似的日志。然后dasd
进程记录default 10:17:42.994236 +0200 dasd DuetActivitySchedulerDaemon Advancing start date for <private> by 6.3 minutes to Wed Sep 13 10:24:03 2017
。无声的推送似乎在那个时候送达。
已经开始使用 iOS 11 GM 进行测试,仍然看到奇怪的行为,日志如 com.apple.fetch.com.troii.timriphone:F613DA:[ name: ApplicationPolicy, policyWeight: 50.000, response: Decision: Must Not Proceed, Score: 0.00 ], FinalDecision: Must Not Proceed
另外 - 我设法通过发送带有一些存根通知的非静默推送来解决我的应用程序,并使用通知服务扩展使用正确的内容填充通知。【参考方案4】:
iOS 11.1 测试版发行说明包括: 通知 已解决的问题 静默推送通知的处理频率更高。 (33278611)
【讨论】:
【参考方案5】:iOS 11.1 Beta 2 也包含
Notifications
Resolved Issues
• Silent push notifications are processed more frequently. (33278611)
在发行说明中 - 现在将对其进行测试。
更新 - 11.10.2017 - iOS 11.1 Beta 2
在“真实世界场景”中使用我们的应用程序 2 天后,这个版本的 iOS 似乎有了真正的改进。我开始谨慎地相信这是固定的。
【讨论】:
我测试了不同的场景:它在前台和后台状态下工作。不幸的是,如果应用程序被用户终止,它就不起作用。终止后设备不会收到任何静默推送,只要用户没有再次主动启动应用程序。你有同样的经历吗? 现在它可以工作了......在大约“停机时间”之后。 5 到 10 分钟后,无声通知按预期工作......对不起我的上一个。评论:) 当用户终止应用程序时,静默推送永远不会起作用 - 请参阅 developer.apple.com/documentation/uikit/uiapplicationdelegate/… “但是,如果用户强制退出应用程序,系统不会自动启动它。” 我看到 iOS11.1 beta 3 的工作方式与 iOS10 非常相似,而且比 iOS11.1 beta 2 好很多。 @Olecramoak 对我来说 iOS11.1 beta 4 的工作方式与 iOS 10 类似。【参考方案6】:Apple Developer Relations 刚刚向我的雷达添加了一条评论:
我们相信这个问题已在最新的 iOS 11.2 测试版中得到解决。
请使用最新的 iOS 测试版进行测试。如果仍有问题,请 使用任何相关日志或信息更新您的错误报告 可以帮助我们调查。
https://developer.apple.com/download/
目前正在安装 iOS 11.2 beta - 将测试静默推送行为
【讨论】:
这是否意味着 iOS 11.1 GM 无法解决问题? :( 很高兴听到这个消息,我们什么时候可以真正期待 iOS11.1 的正式发布? 通知我们,目前无法安装我的应用程序,因为没有适用于 11.2 的 Xcode。 (我从我的设备中删除了该应用程序)【参考方案7】:我的应用程序遇到了类似的问题,直到 iOS 10 我收到推送通知并且 application:didReceiveRemoteNotification:fetchCompletionHandler
被正确调用。但是当更新到 iOS 11 时,推送通知停止工作。
我的代码的问题是,即使我在推送通知有效负载中使用 content-available:1 和 mutable-content:1,后台获取选项也没有打开。但它在 iOS 10 之前一直运行良好。
打开后台获取功能后,它现在正在工作
【讨论】:
不,它不适用于 iOS11 - 只需终止您的应用程序一次,然后它就会停止唤醒您的应用程序。只需阅读本主题中的答案和 cmets 对于终止的应用程序,任何推送通知(静默或一般推送)都不会在应用程序委托中触发委托方法。那是默认行为。 iOS 11.0 没有特殊情况。 这对我没有任何影响。【参考方案8】:iOS 11.4.1、Swift 4
我遇到了静默推送未到达(来自 CloudKit)的问题,我尝试了每个人在这里提到的一切。然后我决定尝试为我的CKNotificationInfo()
对象设置一个空白的alertBody
,如下所示:
let info = CKNotificationInfo()
info.shouldSendContentAvailable = true
info.alertBody = ""
这使得推送以更高的优先级发送(但它们仍然是静默推送),并且我的设备日志中不再出现推送被忽略的错误。
我希望对某人有所帮助。 :)
【讨论】:
CloudKit 也适用于我。如果没有 alertBody,您需要插入设备才能获取 remoteNotifications。非常奇怪的行为......【参考方案9】:所以这确实是 iOS 11 中的一个错误,现在已在 iOS 11 beta 3 中修复。现在,当在前台或后台收到静默推送时,application:didReceiveRemoteNotification:fetchCompletionHandler
会被正确调用。
更新
不,它没有修复,并且在 iOS beta 3 和 4 中仍然存在
【讨论】:
其实不是 :( 在 iOS 11 beta 3 中仍然存在 Apple 也重新打开了错误报告。我会告诉你的 我在 iOS 11 beta 4 中没有收到静默推送。更令人担忧的是,如果应用程序不在前台,它们有时会显示为常规通知。肯定有事! 所以我刚刚安装了 iOS 11 beta 5,它看起来更好,当应用程序处于前台或后台时,通过 didReceiveRemoteNotification 委托传递静默通知一段时间,然后不管它再次停止工作我做什么:/你有同样的行为吗? 如果你测试那会很酷,这让我很头疼。重新启动设备后,无声推送随机工作或不随机工作。我用一个示例项目更新了我的原始帖子,以便我们都使用相同的【参考方案10】:作为一种解决方法,我们正在添加一个“通知”键,并在一个“标题”内添加一个空字符串作为值。 这是唤醒 appDelegate 中的 didReceive 回调。
【讨论】:
这似乎对我有用,也是让 DuetActivitySchedulerDaemon 允许通知唤醒应用程序的解决方法,直到苹果修复错误。 推送包含空标题的 JSON 时,我仍然在控制台上收到消息“忽略没有警报、声音或徽章的通知...”“aps”:“alert”: "title":" " , "content-available":"1" , "gcm.message_id":"0...bb" 这个 JSON 结构适合你吗? 您不应该发送不带引号的 1(可用内容的值)吗? 这就是 Google Firebase 格式化 Json(“1”)的方式,并且它始终有效。只是带有 dasd 废话的 iOS 11 正在制造一个问题。您能否发布一个为您工作的 Json 示例? 所以我在 iOS 11.1 上观察到的是,如果设备使用电池运行(未充电)并且电池电量低于 20%,即使在低能耗模式下,也不会提供静音推送没有激活。这是不好的。 iOS 11 上的静默推送根本不可靠,几乎没用。【参考方案11】:在撰写此答案时,我面临与Bill Dunay's 答案完全相同的问题。
我的要求是在应用程序处于前台时接收静默通知,而在应用程序处于后台/未运行时接收任何通知。我的解决方法是这样的。我不使用徽章,因此将其设置为零对我来说不是问题。
"aps" :
"badge" : 0,
"sound" : ""
,
"mydata":
"foo": "bar"
请注意,我故意不使用“内容可用”。导致 iOS 优化逻辑延迟/取消通知传递的设置。
【讨论】:
【参考方案12】:对于某些通知,我遇到了同样的问题(不一定是无声的)。
查看所有更新和答案后,我可以添加两个可能有帮助的更新:
我发现在接收通知的同时访问UIApplication.shared.isRegisteredForRemoteNotifications
方法会导致应用程序停止而不向 Xcode 报告任何内容。在收到访问该方法的通知后,检查您是否正在运行某些代码。 (isRegisteredForRemoteNotifications locking UI with semaphore_wait_trap)。
"title-loc-args" : [3333]
不接受字面意义上的 3333,而是接受它作为字符串 "title-loc-args" : ["3333"]
。在我访问上述方法后,这使我的整个界面停滞不前,仅在 iOS 11 上,它适用于 iOS 12。
我还发现,使用完全相同的代码,它可以在 iOS 12.0 (16A5366a) 上正常运行。但在 iOS 11 上它正在发生。
【讨论】:
【参考方案13】:在我的情况下,在服务器站点上完成工作后使用静默通知来更新 ui,因此在应用程序中包含不相关的内容很痛苦。因为我们的静默通知负载甚至包含标题和正文,所以我实现了这些方法以在活动/非活动应用程序中获取工作通知,而不是充电,后台应用程序刷新关闭,甚至处于低功耗状态。
为了让它工作,我添加委托并使用UNUserNotificationCenterDelegate
协议和willPresent notification
(iOS 10+) 方法创建扩展,每次都会使用正确的有效负载触发。要在应用程序处于活动状态时不显示通知,只需使用徽章或声音调用完成。
我最终得到了这样的结果
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
// MARK: - Lifecycle
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
UNUserNotificationCenter.current().delegate = self
return true
//this was only method to handle notifications before
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
//process silent notification
completionHandler(UIBackgroundFetchResult.newData)
extension AppDelegate : UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
//proces notification when app is active with `notification.request.content.userInfo`
if UIApplication.shared.applicationState == .active
completionHandler(.badge)
else
completionHandler(.alert)
当应用程序处于后台和静默通知时,要使这些状态正常工作,请不要调用我的方法,我会直接在 applicationDidBecomeActive
中通过以下方式从通知中心收到通知:
UNUserNotificationCenter.current().getDeliveredNotifications (notifications) in
debugLog(message: "unprocessed notification count: \(notifications.count)")
if notifications.count > 0
notifications.forEach( (notification) in
DispatchQueue.main.async
//handle `notification.request.content.userInfo`
)
【讨论】:
【参考方案14】:就我而言,iPhone 设置中的“后台应用刷新”已关闭。由于此推送通知已发送到设备,但未发送到应用程序。打开后台应用刷新会在应用中接收静默推送。
这可能不是这个问题的实际答案,以防万一有人需要检查。
【讨论】:
以上是关于iOS 11 上的静默推送未发送到应用程序的主要内容,如果未能解决你的问题,请参考以下文章
静默推送通知是不是能够唤醒 ios 中处于未运行状态的应用程序?