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

RN 0.78.0升级Swift后出现unrecognized selector崩溃问题求助

升级React Native 0.78.0后Swift迁移导致启动崩溃问题解决

问题背景

将React Native升级至0.78.0版本,完成从Objective-C++到Swift的迁移后,应用构建成功但启动时崩溃,Xcode抛出如下错误:

Thread 1: "-[GUL_MyApp.AppDelegate pushRegistry:didUpdatePushCredentials:forType:]: unrecognized selector sent to instance"

迁移前后代码对比

升级前的Objective-C++代码(AppDelegate.mm)

#import "AppDelegate.h"
#import "RNCallKeep.h"

#import <React/RCTBundleURLProvider.h>

#import <PushKit/PushKit.h>
#import "RNVoipPushNotificationManager.h" 
@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [RNVoipPushNotificationManager voipRegistration];

  self.moduleName = @"MyApp";
  self.initialProps = @{};


  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  return [self bundleURL];
}
 
- (NSURL *)bundleURL
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}


- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
  restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler
{
  return [RNCallKeep application:application
           continueUserActivity:userActivity
             restorationHandler:restorationHandler];
}


/* Add PushKit delegate method */

// --- Handle updated push credentials
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
  // Register VoIP push token (a property of PKPushCredentials) with server
  [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type];
}

- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type
{
  // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token.
}

// --- Handle incoming pushes
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {

  // Process the received push
  [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];


    [RNCallKeep reportNewIncomingCall: uuid
                             <rest of params>,
                withCompletionHandler: completion];
}


@end

迁移后的Swift代码(AppDelegate.swift)

import UIKit
import RNCallKeep
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import PushKit
import RNVoipPushNotification


@main
class AppDelegate: RCTAppDelegate {
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    
    RNVoipPushNotificationManager.voipRegistration()
    self.moduleName = "MyApp"
    self.dependencyProvider = RCTAppDependencyProvider()
 
    self.initialProps = [:]
 
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
 
  override func sourceURL(for bridge: RCTBridge) -> URL? {
    self.bundleURL()
  }
 
  override func bundleURL() -> URL? {
#if DEBUG
    RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
    Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
  }

  func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([Any]?) -> Void
) -> Bool {
    return RNCallKeep.application(
        application,
        continue: userActivity,
        restorationHandler: restorationHandler)
}
  
  func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
      // Register VoIP push token (a property of PKPushCredentials) with server
      RNVoipPushNotificationManager.didUpdate(pushCredentials, forType: type.rawValue)
  }

  func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
      // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token.
  }
  
  
  func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    
          RNCallKeep.reportNewIncomingCall(
              <rest of params>,
              withCompletionHandler: completion)
      }
  }
  
}

问题原因

崩溃根源是Swift版AppDelegate未显式遵循PKPushRegistryDelegate协议。Objective-C中无需显式声明协议,只要实现对应方法就能被系统调用;但Swift要求必须明确声明遵循协议,否则系统无法识别已实现的回调方法,从而触发"无法识别的选择器"错误。

修复方案

1. 添加协议声明

在AppDelegate类定义中添加PKPushRegistryDelegate协议:

@main
class AppDelegate: RCTAppDelegate, PKPushRegistryDelegate {
    // ... 现有代码
}

2. 修正RNVoipPushNotificationManager调用

确保Swift中调用的方法签名与OC版本对齐,原OC方法didUpdatePushCredentials:forType:对应的Swift桥接方法应为didUpdatePushCredentials(_:forType:),调整调用代码:

func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
    RNVoipPushNotificationManager.didUpdatePushCredentials(pushCredentials, forType: type.rawValue as String)
}

3. 补全遗漏的Voip通知处理代码

迁移后的Swift代码中遗漏了原OC里的RNVoipPushNotificationManager调用,补全到didReceiveIncomingPushWith方法中:

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    // 补全Voip通知处理
    RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue as String)
    
    RNCallKeep.reportNewIncomingCall(
        // ... 现有参数
        withCompletionHandler: completion)
}

4. 清理缓存并重新构建

执行Xcode的清理操作(Cmd+Shift+K),然后重新编译项目,确保协议变更和代码修改被正确识别。

内容的提问来源于stack exchange,提问作者Irfan wani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 02:10:56