You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PushKit代理移至独立Manager类后方法未触发的问题

解决PushKit代理迁移至独立类后不触发的问题

问题核心原因

迁移后代理方法不被调用的关键是对象生命周期被提前回收:

  • 在AppDelegate中创建的VoIPNotificationManager是局部变量,执行完注册代码后就被ARC自动回收;
  • registerForVoIPNotifications()内部的PKPushRegistry也是局部变量,同样会被释放,导致代理对象不存在,无法触发回调。
    而原AppDelegate是全局生命周期的对象,PKPushRegistry的代理(AppDelegate实例)不会被回收,所以功能正常。

解决方案

要保证VoIPNotificationManager和PKPushRegistry的生命周期与应用一致,需要:

  1. 将VoIPNotificationManager声明为AppDelegate的全局属性;
  2. 将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:45:37