iOS 13 Xcode 11:PKPushKit 和 APNS 在一个应用程序中

Posted

技术标签:

【中文标题】iOS 13 Xcode 11:PKPushKit 和 APNS 在一个应用程序中【英文标题】:iOS 13 Xcode 11: PKPushKit and APNS in one App 【发布时间】:2020-05-09 12:01:39 【问题描述】:

2020 年 4 月 30 日之后,Apple 不再接受来自 Xcode 10 的构建。它要求上传适用于 ios 13 SDK 的构建。我尝试了同样的方法,现在我遇到了以下错误而崩溃。

[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes]

我的应用程序是一个社交媒体应用程序,其中包含来自 Twilio 的音频/视频通话、聊天、Feed 帖子和许多其他功能。它包含用于多种目的的推送通知。现在应用程序在收到推送时要么没有收到推送,要么崩溃(在后台或终止状态)。当我搜索时,我发现如果我的应用程序没有显示 Callkit 来电屏幕或应用程序没有处理 VOIP 通知,我不允许使用 PushKit。 我的应用程序包含两种通知,即 VOIP 和非 VOIP。所以,这意味着我必须同时使用两个通知,即 PushKit 和 APNS。

您能帮我如何在单个应用中实现这两个通知吗? 我只能通过 PushKit 实现我的目标吗? 我需要在我的应用中进行哪些更改才能实施? 还有其他的解决方案吗?

寻找您的建议。

【问题讨论】:

看这里:***.com/questions/56788314/… @pepsy 没有从这个链接得到正确的解决方案 @pepsy 我能得到一些上述解决方案的实际例子吗? 【参考方案1】:

简短的回答是:

你需要在你的应用中实现这两个推送

您只能将 PushKit 用于代表应用程序新来电的推送,并且当您通过 PushKit 收到推送时,您必须始终在 CallKit 屏幕上显示新来电。

对于您可能想要发送的其他通知,您必须使用常规推送。


如何实现?

首先,您的应用需要向 Apple 注册两个推送并获取两个推送令牌。

要注册 VoIP,您将使用 PushKit:

class PushService 
    private var voipPushRegistry: PKPushRegistry?

    func registerForVoipPushes() 
        voipPushRegistry = PKPushRegistry(queue: DispatchQueue.main)
        voipPushRegistry!.delegate = self
        voipPushRegistry!.desiredPushTypes = Set([PKPushType.voIP])
    

使用 PKPushRegistryDelegate,您可以获得 VoIP 令牌:

extension PushService: PKPushRegistryDelegate 
    func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) 
        print("VoIP token: \(pushCredentials.token)")
    

注册常规推送:

let center = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .badge, .sound];
center.requestAuthorization(options: options) 
    (granted, error) in
    guard granted else 
        return
    

    DispatchQueue.main.async 
        UIApplication.shared.registerForRemoteNotifications()
    

您将在 AppDelegate 中获得常规推送令牌:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) 
    print("Regular pushes token: \(deviceToken)")


现在您拥有两个令牌,您将把它们都发送到您的服务器。您必须重构服务器端以接受这两个令牌,并为您发送给用户的每种推送类型选择正确的一个。

您可以发送 4 种不同类型的推送:

VoIP(令牌:VoIP):仅用于通知来电。 没有例外。

Regular(令牌:Regular):当您需要编写通知消息的所有信息在您的服务器端都可用时使用它。您的应用在收到此推送时不会运行任何代码,iOS 只会显示通知,不会唤醒您的应用

通知服务扩展(令牌:常规):当您需要一些仅在客户端可用的信息时,您可以使用此推送。要使用它,只需将标志 mutable-content: 1 添加到您的推送(在您的服务器端),并在您的应用程序中实现通知服务应用程序扩展。当 iOS 收到带有此标志的推送时,它会唤醒您的应用程序扩展并让您在那里运行一些代码。它不会唤醒您的应用程序,但您可以使用应用程序组或钥匙串在您的应用程序及其扩展程序之间共享信息。 此通知将始终显示警告横幅。

静音(令牌:常规):此推送将在后台唤醒您的应用程序,让您运行一些来,如果您不想显示通知横幅,则可以不显示。这意味着您可以使用此推送来运行一些代码,而用户甚至不会注意到。要使用它,请将标志 content-available: 1 添加到您的推送中。但请注意:此推送的优先级非常低。 静默推送可能会被延迟甚至完全忽略。


如何处理应用中的推送?

VoIP 推送将由您的 PKPushRegistryDelegate 实现处理。

extension PushService: PKPushRegistryDelegate 
    [...]

    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) 
        print("VoIP push received")
        //TODO: report a new incoming call through CallKit
    

可变内容通知将由您的Notification Service Extension 处理。

静默推送将由您的 AppDelegate 处理:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) 
    print("Silent push received")

【讨论】:

WhatsApp 如何仍然使用 VoIP 推送所有消息?他们正在使用一些可以解决的代码。 (尚未回复developer.apple.com/forums/thread/130650) @JoaoBelemJr。有一些可能的变通方法,应用商店中提供的应用都不接受这些变通方法,但您也许可以在企业应用上使用它们。其中一些正在使用较旧的 iOS SDK,使用 iOS 13 之前的 SDK 覆盖当前 SDK 的特定部分,或者使用方法调配来防止崩溃。 ***.com/questions/59940847/… 我猜 WhatsApp 案例是关于一个特定的不受限制的权利,它允许不报告来电。 (它称为 com.apple.developer.pushkit.unrestricted-voip)。 developer.apple.com/forums/thread/… @JoaoBelemJr。是的,确实如此。我搜索了有关此权利的更多信息,但找不到任何有关它的官方文档。感觉像是被秘密授予了一些更大的公司,没有其他人能够使用它,也没有请求许可。

以上是关于iOS 13 Xcode 11:PKPushKit 和 APNS 在一个应用程序中的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 11.3 / iOS 13.3 NavigationLink 仅推送一次

iOS 布局在 Xcode 11 上的 iOS 13 上中断 - 未调用 traitCollectionDidChange

Xcode 11 beta -playbackState 仅在 iOS 13.0 或更新版本中可用

在 iOS13 + xcode 11 中隐藏导航栏

为啥 UICollectionView 在 Xcode 11 (ios 13) 中省略 Line/Intrim 间距?

iOS 13.3 (Xcode 11.3.1) 下的模拟器无法正常运行