iOS原生模块didRegisterForRemoteNotificationsWithDeviceToken无法回调React Native
解决iOS React Native自定义推送模块无法回调Token的问题
核心问题分析
代码存在三个关键问题:
- AppDelegate中创建了两个不同的PushNotificationManager实例,导致回调无法关联到RN调用时使用的单例
- Swift模块中未实现RN端调用的
requestPermission方法 - 回调RN时未确保在主线程执行,违反RN原生模块的线程要求
具体修复步骤
1. 统一使用单例实例设置通知代理
在AppDelegate的didFinishLaunchingWithOptions中,不要新建PushNotificationManager实例,直接使用单例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.moduleName = @"medux"; self.initialProps = @{}; UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; // 使用单例而非新建实例 center.delegate = PushNotificationManager.shared; return [super application:application didFinishLaunchingWithOptions:launchOptions]; }
2. 在Swift模块中实现requestPermission方法
RN端调用了这个方法,但Swift代码里没有实现,导致后续注册流程无法触发。添加以下代码到PushNotificationManager类中:
@objc func requestPermission(_ callback: @escaping RCTResponseSenderBlock) { DispatchQueue.main.async { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if let error = error { callback([error.localizedDescription, NSNull()]) } else { callback([NSNull(), granted]) } } } }
3. 确保RN回调在主线程执行
RN的RCTResponseSenderBlock必须在主线程调用,修改注册成功/失败回调方法:
@objc func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { self.deviceToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() print("Device token set: \(String(describing: self.deviceToken))") // 回到主线程触发RN回调 DispatchQueue.main.async { self.callback?([NSNull(), self.deviceToken]) // 回调后清空引用,避免内存泄漏 self.callback = nil } } @objc func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("Failed to register for remote notifications with error: \(error)") DispatchQueue.main.async { self.callback?([error.localizedDescription, NSNull()]) self.callback = nil } }
4. 验证设备Token格式一致性(可选)
AppDelegate中手动格式化Token的代码可以保留,但建议和Swift模块中的格式保持一致,避免日志混淆;也可以直接移除AppDelegate中的Token格式化代码,统一使用Swift模块的逻辑。
额外检查项
- 确保Xcode中已开启Push Notifications能力(Target -> Signing & Capabilities -> + Capability 添加Push Notifications)
- 必须使用真实iOS设备测试(模拟器无法获取推送Token)
- 确认Apple开发者账号已配置对应环境的推送证书(开发/生产)
内容的提问来源于stack exchange,提问作者thelittlemaster
相关产品推荐
相关产品推荐

