PushKit delegate methods not being called after putting them in a separate manager class

huangapple go评论69阅读模式
英文:

PushKit delegate methods not being called after putting them in a separate manager class

问题

在应用程序委托中添加PushKit代理后,它能够完美工作。以下是代码:

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions:
                     [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        self.voipRegistration()
        
        return true
    }
    
    // 注册VoIP通知
    func voipRegistration() {
        // 创建推送注册对象
        let mainQueue = DispatchQueue.main
        let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [.voIP]
    }
}

// MARK: - PKPushRegistryDelegate
extension AppDelegate: PKPushRegistryDelegate {
    
    // 处理更新的推送凭据
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        print("pushRegistry -> deviceToken: \(deviceToken)")
    }
    
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        print("pushRegistry: didInvalidatePushTokenForType:")
    }
    
    // 处理传入推送
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        // 显示呼叫屏幕
        if type == .voIP {
            print("VoIP")
        } else {
            print("Nope")
        }

        if UIApplication.shared.applicationState == UIApplication.State.active {
            print("Active")
        } else {
            let config = CallKit.CXProviderConfiguration()
            config.supportsVideo = true
            let provider = CXProvider(configuration: config)

            let testCallKit = TestCallKitFile()
            testCallKit.recieveACall(provider: provider)
        }
    }
}

这段代码之所以工作,是因为从didUpdate credentials方法中打印了一个设备令牌。但是,当将代理方法放在一个单独的类中时,它们不会被调用(我知道这是因为令牌没有被打印)。以下是代码:

VoIPNotificationManager类

class VoIPNotificationManager: NSObject, PKPushRegistryDelegate {
    
    func registerForVoIPNotifications() {
        let mainQueue = DispatchQueue.main
        let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [.voIP]
    }
    
    // 处理更新的推送凭据
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        print("pushRegistry -> deviceToken: \(deviceToken)")
    }
    
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        print("pushRegistry: didInvalidatePushTokenForType:")
    }
    
    // 处理传入推送
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        // 显示呼叫屏幕
        if type == .voIP {
            print("VoIP")
        } else {
            print("Nope")
        }
        
        if UIApplication.shared.applicationState == UIApplication.State.active {
            print("Active")
        } else {
            let config = CallKit.CXProviderConfiguration()
            config.supportsVideo = true
            let provider = CXProvider(configuration: config)
            
            let testCallKit = TestCallKitFile()
            testCallKit.recieveACall(provider: provider)
        }
    }
}

然后,在应用程序委托的didFinishLaunchingWithOptions方法中调用它,如下所示:

// 注册VoIP通知
let voipNotificationManager = VoIPNotificationManager()
voipNotificationManager.registerForVoIPNotifications()

此外,这是一个SwiftUI应用。

英文:

When I add the PushKit delegates in the App Delegate, it works perfectly. Here's the code:

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions:
                     [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        self.voipRegistration()
        
        return true
    }
    
    // Register for VoIP notifications
        func voipRegistration() {
            // Create a push registry object
            let mainQueue = DispatchQueue.main
            let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
            voipRegistry.delegate = self
            voipRegistry.desiredPushTypes = [.voIP]
        }
}


// MARK: - PKPushRegistryDelegate
extension AppDelegate : PKPushRegistryDelegate {

    // Handle updated push credentials
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        print("pushRegistry -> deviceToken :\(deviceToken)")
    }

    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        print("pushRegistry:didInvalidatePushTokenForType:")
    }

    // Handle incoming pushes
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        // Show call screen
        if type == .voIP {
            print("VoIP")
        } else {
            print("Nope")
        }

        if UIApplication.shared.applicationState == UIApplication.State.active {
            print("Active")

        } else {

            let config = CallKit.CXProviderConfiguration()
            config.supportsVideo = true
            let provider = CXProvider(configuration: config)

            let testCallKit = TestCallKitFile()
            testCallKit.recieveACall(provider: provider)
        }
    }
}

This code works because a token is being printed from the didUpdate credentials method. But when I put the delegate methods in a separate class, they are not being called (I know that because the token is not being printed). Here's the code:

VoIPNotificationManager class

class VoIPNotificationManager: NSObject, PKPushRegistryDelegate {
    
    func registerForVoIPNotifications() {
        let mainQueue = DispatchQueue.main
        let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [.voIP]
    }
    
    // Handle updated push credentials
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        print("pushRegistry -> deviceToken :\(deviceToken)")
    }
    
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        print("pushRegistry:didInvalidatePushTokenForType:")
    }
    
    // Handle incoming pushes
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        // Show call screen
        if type == .voIP {
            print("VoIP")
        } else {
            print("Nope")
        }
        
        if UIApplication.shared.applicationState == UIApplication.State.active {
            print("Active")
            
        } else {
            
            let config = CallKit.CXProviderConfiguration()
            config.supportsVideo = true
            let provider = CXProvider(configuration: config)
            
            let testCallKit = TestCallKitFile()
            testCallKit.recieveACall(provider: provider)
        }
    }
}

And I am calling this in the appDelegate's didFinishLaunchingWithOptions method like so:

// Register for voip notifs
let voipNotificationManager = VoIPNotificationManager()
voipNotificationManager.registerForVoIPNotifications()

Also, this is a SwiftUI app.

答案1

得分: 1

看起来你没有在didFinishLaunchingWithOptions方法之外保存对voipNotificationManager的引用。我说得对吗?如果是这样,那么在didFinishLaunchingWithOptions完成后,该管理器将被释放,因为没有剩余的强引用。

以下是内存管理在Swift中的工作方式的链接:链接

我建议你将voipNotificationManager作为应用程序代理的属性,就像这样:

class AppDelegate: UIResponder, UIApplicationDelegate {

    let voipNotificationManager = VoIPNotificationManager()

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions:
                     [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        voipNotificationManager.registerForVoIPNotifications()

        return true
    }

   ...

}
英文:

It looks like you don't store a reference to your voipNotificationManager outside of the didFinishLaunchingWithOptions method.
Am I right?
If so, the manager just gets deallocated after the didFinishLaunchingWithOptions finishes. As there are no strong references left.

Here is how memory management works in swift link

What I would suggest you do is make your voipNotificationManager a property on the app delegate like so

class AppDelegate: UIResponder, UIApplicationDelegate {

    let voipNotificationManager = VoIPNotificationManager()

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions:
                     [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        voipNotificationManager.registerForVoIPNotifications()

        return true
    }

   ...

}

huangapple
  • 本文由 发表于 2023年2月10日 12:03:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75406820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定