英文:
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
    }
   ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论