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

Swift iOS 13 Xcode 11:PKPushKit和APN在一个应用程序中,swift,apple-push-notifications,ios13,xcode11,pushkit,Swift,Apple Push Notifications,Ios13,Xcode11,Pushkit,2020年4月30日之后,苹果不再接受Xcode 10的构建。它要求上传iOS 13 SDK的构建。我尝试了同样的方法,现在我得到了以下错误 [PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes] 我的应用程序是一个社交媒体应用程序,它包含来自Twilio的音频/视频通话、聊天、feeds post和许多其他功能。它包含用于多种目的的推送通知。现在,应用程序要么没有接收推送,要么在接收推送时崩溃(处于后台或已终止状态)。当我搜索时

2020年4月30日之后,苹果不再接受Xcode 10的构建。它要求上传iOS 13 SDK的构建。我尝试了同样的方法,现在我得到了以下错误

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

您能帮助我如何在单个应用程序中实现这两种通知吗? 我只能通过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)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print("Silent push received")
}

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

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

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

  • 常规(token:Regular):在服务器端有编写通知消息所需的所有信息时使用它。收到此推送时,您的应用程序不会运行任何代码,iOS将只显示通知,不会唤醒您的应用程序

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

  • 无声(令牌:常规):此推送将在后台唤醒您的应用程序,让您运行一些应用程序,如果您不想,您可能不会显示通知横幅。这意味着您可以使用这个推送来运行一些代码,而用户甚至不会注意到。要使用它,请将标志
    内容可用: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
    }
}
可变内容通知将由您的管理员处理

无声推送将由AppDelegate处理:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    print("Regular pushes token: \(deviceToken)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print("Silent push received")
}
简单的回答是:

您需要在应用程序中实现两个推送

您只能将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)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print("Silent push received")
}

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

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

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

  • 常规(token:Regular):在服务器端有编写通知消息所需的所有信息时使用它。收到此推送时,您的应用程序不会运行任何代码,iOS将只显示通知,不会唤醒您的应用程序

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

  • 静默(标记:常规):此推送将