在 iOS 13 设备中无法在后台/挂起状态下接收 VoIP 消息

Posted

技术标签:

【中文标题】在 iOS 13 设备中无法在后台/挂起状态下接收 VoIP 消息【英文标题】:Cannot receive VoIP messages in background/suspended state in iOS 13 Devices 【发布时间】:2019-12-03 05:02:32 【问题描述】:

我正在开发一个聊天应用程序。为了增强消息传递体验,我使用 VoIP 推送将消息传递到处于后台/已终止状态的应用程序。我猜这就是whatsapp的做法。它在 13.0 之前的 ios 版本的设备上运行良好。但是,在 iOS 13 设备上,推送仅处于前台状态。在后台状态下,我无法在didReceiveIncomingPushWith 委托方法中获得回调。我浏览了一些在线博客,其中写到苹果现在将其限制为仅用于通话目的。人们提出的另一件事是,如果应用程序分布在 XCode 10 上,即使用 iOS 12 SDK 编译,那么它也应该可以工作。但是,无论我使用什么 XCode,它都不适用于我的情况。我的目标是即使应用程序像whatsapp一样在后台被杀死/在后台也能将消息传递给用户。对此的任何想法/指导都将受到高度赞赏。谢谢

【问题讨论】:

【参考方案1】:

我遇到了完全相同的问题;我的问题是在 iOS 13 上有一个新的 pushkit 委托方法:

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void

它不同于原型末尾的完成处理程序(现已弃用)。 文档声明您必须调用完成处理程序(即使是无效的)来告诉 CallKit 该调用已被处理。 如果不遵守,将禁止您的应用在后台或强制退出状态下接收 pushkit 通知。当应用程序在前台时它仍然有效。

我解决了将以下代码添加到我的应用程序的问题:

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) 
        NSLog("Got new callback incoming notification")
        self.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type)
        DispatchQueue.main.async 
          completion()
        
    

附:要清除 banned 状态(在我的测试中 2-3 次合规失败后触发),您需要从设备中完全删除应用程序并重新开始。

【讨论】:

嗨@alienpenguin,我按照你说的做了。现在我可以在后台收到通知,但应用程序崩溃了。并且在 3-4 次之后,push 也停止了。还请告诉我“self.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type)”这个你正在调用的方法。当我尝试调用它时,它会出错。 在回调中,您必须调用 reportNewIncomingCall 并告诉 callkit 有新的呼叫到达。如果你不这样做,应用程序将会崩溃,并且在几次之后它不会再次收到推送通知,直到你重新安装它 @Alienpenguin 谢谢你的信息【参考方案2】:

您需要在 iOS 13 中使用 CallKit。

对于使用 iOS 13 SDK 或更高版本构建的应用,PushKit 要求您在处理 VoIP 呼叫时使用 CallKit。 CallKit 确保在用户设备上提供通话相关服务的应用在用户设备上无缝协作,并尊重“请勿打扰”等功能

还有

如果您的应用无法支持 CallKit,则无法使用 PushKit 处理推送通知。相反,请使用 UserNotifications 框架配置您的应用的推送通知支持。

Apple's documentation

【讨论】:

感谢您的回复。但是我的问题有点不同。我正在使用 Callkit 和 PushKit 进行音频/视频通话,它工作正常。但我也使用 Pushkit 在后台/已终止状态下传递即时消息。这在 iOS 13 上停止工作。我只需要知道我是否仍然可以利用 Pushkit 功能或使用其他东西在后台传递消息。 是的,除了 UserNotification,我不知道任何其他方式。但我认为这将是面向用户的,不会完全是背景。【参考方案3】:

是的,我们可以为它使用通知内容扩展。 我们可以告诉我们的消息服务器消息已被传递。 如果需要,我们还可以在主应用程序和内容扩展之间共享本地数据库。 如果我们在 APNS 中传递实际消息,我们可以从服务器获取实际消息。 通知内容扩展将提供大约 30 秒的窗口来同步数据。

【讨论】:

如果应用被杀了怎么办?它还在为你工作吗? 是的,当主应用程序处于后台或终止状态时,扩展程序会被调用事件。我们可以告诉服务器消息已经从扩展传递过来了。【参考方案4】:

一般而言,VoIP 实施包含以下步骤:

    添加 VoIP 功能 注册 voip-Pushes:
private func registerForVoIPPushes() 
   voipRegistry = PKPushRegistry(queue: nil)
   voipRegistry?.delegate = self
   voipRegistry?.desiredPushTypes = [.voIP]

    UNUserNotificationCenterDelegate 的实现
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void)

    Offcourse服务器端部分实现

    !最常见的问题: 一旦应用程序收到 VoIP 通知并且没有将其报告给 CXProvider 对象,它就不会再收到通知,直到您重新安装它。因此,请务必报告您获得的每个 VoIP。

【讨论】:

以上是关于在 iOS 13 设备中无法在后台/挂起状态下接收 VoIP 消息的主要内容,如果未能解决你的问题,请参考以下文章

即使应用程序处于挂起状态,如何在 ios 中运行后台服务

iOS - 在设备设置中,如果我更改时间,即使在应用程序后台、已终止状态下也应该得到通知

RN - iOS端后台挂起后30s重启问题处理过程与心得

iOS 后台挂起的一些坑

RN - iOS端后台挂起后30s重启问题处理过程与心得

应用程序处于非活动状态时无法接收静默通知 iOS