Как правильно получать PUSH-уведомления?

Я пишу приложение VoIP с использованием Xcode 9.2, Swift 4.0, минимальная версия iOS 10.3. Я хочу получать входящий звонок, даже если iPhone находится в спящем режиме (как в WhatsApp или Viber). Я уже знаю, что я должен использовать CallKit для этого. Но я не знаю, как правильно получать PUSH-уведомления. Я имею в виду, у меня есть два способа, как их получить. Сначала в AppDelegate.swift, пожалуйста, посмотрите (этот метод работает):

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        //Getting permissions for Notifications
        //222
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
        }
        application.registerForRemoteNotifications()
        //222

        return true
    }

    //For PUSH Notifications settings

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("NOTIFICATION ERROR: \(error)")
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let pushToken = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}).lowercased()
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // Receiving call?
    }

}

Но, независимо от того, что я делаю, он не запускает входящий звонок, если iPhone спит. В последнее время я увидел, что есть другой способ получать PUSH-уведомления. Пожалуйста, посмотрите:

import UIKit
import CallKit
import PushKit

class ViewController: UIViewController, CXProviderDelegate, PKPushRegistryDelegate {

    override func viewDidLoad() {
        let registry = PKPushRegistry(queue: nil)
        registry.delegate = self
        registry.desiredPushTypes = [PKPushType.voIP]
    }

    func providerDidReset(_ provider: CXProvider) {
    }

    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        action.fulfill()
    }

    func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
        action.fulfill()
    }

    func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
        print(pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined())
    }

    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        // Receive call?
    }

}

Проблема в том, что в первом методе у меня есть этот токен PUSH: 9bcf73ac3d6a68be07c26d8b6a972f5b716cd5308f1a19048b62d19b9b8d4bd1

Второй метод возвращает мне этот токен PUSH: 1e40fafb2963161b1bcf1bdde00d625a879c6934e19e2fb32f62b1c9272e956f

И они не равны! Как это может быть? Итак, главный вопрос: как получать PUSH-уведомления и в чем разница между методами AppDelegate и PushKit и какой токен является правильным?

Спасибо за любую помощь!

2 ответа

Существует два типа уведомлений (на самом деле больше, но, в данном случае, только два): PUSH-уведомления и VoIP-уведомления. У них разные токены и разная система получения. Сервисы VoIP существуют только для вызовов (Apple CallKit), а сервис PUSH существует для сообщений и других уведомлений. Таким образом, на самом деле оба эти метода необходимы, и один не заменяет другой. И для того и для другого способа требуются разные сертификаты в учетной записи разработчика Apple: служба push-уведомлений Apple SSL для PUSH-уведомлений и сертификат VoIP-услуг для VoIP. Спасибо всем за помощь! Будьте свободны отредактировать это, если вы видите ошибку.

Прежде всего удалите эту строку application.registerForRemoteNotifications()

Теперь перейдем к пускиту ниже, метод будет иметь правильный токен

   func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, forType type: PKPushType) {
    print("\(#function) voip token: \(credentials.token)")

    let deviceToken = credentials.token.reduce("", {$0 + String(format: "%02X", $1) })
    print("\(#function) token is: \(deviceToken)")}

и Push-kit Framework не имеет пользовательского интерфейса, такого как удаленное или локальное уведомление, вам нужно запускать локальное уведомление каждый раз, когда вызывается метод ниже

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    // Receive call?
}
Другие вопросы по тегам