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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 11:45:00