PushKit代理移至独立Manager类后方法未触发的问题
解决PushKit代理迁移至独立类后不触发的问题
问题核心原因
迁移后代理方法不被调用的关键是对象生命周期被提前回收:
- 在AppDelegate中创建的
VoIPNotificationManager是局部变量,执行完注册代码后就被ARC自动回收; registerForVoIPNotifications()内部的PKPushRegistry也是局部变量,同样会被释放,导致代理对象不存在,无法触发回调。
而原AppDelegate是全局生命周期的对象,PKPushRegistry的代理(AppDelegate实例)不会被回收,所以功能正常。
解决方案
要保证VoIPNotificationManager和PKPushRegistry的生命周期与应用一致,需要:
- 将
VoIPNotificationManager声明为AppDelegate的全局属性; - 将
PKPushRegistry声明为VoIPNotificationManager的实例属性,避免被提前释放。
修改后的代码
1. 重构VoIPNotificationManager类
class VoIPNotificationManager: NSObject, PKPushRegistryDelegate { // 将PKPushRegistry改为实例属性,保持强引用 private let voipRegistry: PKPushRegistry override init() { let mainQueue = DispatchQueue.main voipRegistry = PKPushRegistry(queue: mainQueue) super.init() voipRegistry.delegate = self voipRegistry.desiredPushTypes = [.voIP] } // 注册方法可保留用于后续扩展,核心注册逻辑已移至init func registerForVoIPNotifications() {} // MARK: - 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 == .active { print("Active") } else { let config = CXProviderConfiguration() config.supportsVideo = true let provider = CXProvider(configuration: config) let testCallKit = TestCallKitFile() testCallKit.recieveACall(provider: provider) } completion() // 必须调用,否则系统会判定推送处理超时 } }
2. 修改AppDelegate中的调用方式
class AppDelegate: UIResponder, UIApplicationDelegate { // 声明全局属性,持有VoIPNotificationManager实例 private let voipNotificationManager = VoIPNotificationManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() voipNotificationManager.registerForVoIPNotifications() return true } }
额外注意事项
- 务必确保
PKPushRegistry及其代理对象的生命周期覆盖应用运行全程,否则代理回调会失效; - 在处理VoIP推送的
didReceiveIncomingPushWith方法中,必须调用completion()闭包,否则系统会限制应用后续的推送接收权限。
内容的提问来源于stack exchange,提问作者Abdullah Ajmal
相关产品推荐
相关产品推荐

