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

iOS 13 Xcode 11: PKPushKit and APNS in one App

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

[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes]

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

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

正在寻找您的建议。

简短的回答是:

您需要在您的应用中实现这两种推送

您只能将 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 (token: Regular): 当你写通知消息所需的所有信息在你的服务器端可用时使用它。您的应用程序在收到此推送时不会 运行 任何代码,iOS 只会显示通知,不会唤醒您的应用程序

  • Notification Service Extension (token: Regular): 当你需要一些只能在客户端获得的信息时,你可以使用这个推送。要使用它,只需将标志 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")
}