iOS生产构建启动崩溃:EXExpoAppDelegate收到未识别选择器
问题分析与修复方案
崩溃根源
这个启动崩溃的核心原因是:
- 生产环境中你设置了
EXUpdatesAppController的代理为AppDelegate自身,但AppDelegate既未遵守EXUpdatesAppControllerDelegate协议,也未实现代理要求的appController:didStartWithSuccess:方法,导致系统调用不存在的方法抛出异常。 - 代码中存在重复初始化React Native实例、重复创建
UIWindow的逻辑,进一步打乱了启动流程。
具体修复步骤
1. 导入Expo Updates相关头文件
在AppDelegate.mm顶部添加:
#import <EXUpdates/EXUpdatesAppController.h> #import <EXUpdates/EXUpdatesAppControllerDelegate.h>
2. 让AppDelegate遵守代理协议
修改@interface声明,添加EXUpdatesAppControllerDelegate协议,并新增共享的bridge属性避免重复创建:
@interface AppDelegate () <RCTBridgeDelegate, EXUpdatesAppControllerDelegate> @property (nonatomic, strong) NSDictionary *launchOptions; @property (nonatomic, strong) RCTBridge *bridge; // 新增:共享bridge实例 @end
3. 实现代理要求的方法
在@implementation块中添加EXUpdatesAppControllerDelegate的必要实现:
#pragma mark - EXUpdatesAppControllerDelegate - (void)appController:(EXUpdatesAppController *)appController didStartWithSuccess:(BOOL)success { // 初始化React Native实例,统一使用共享bridge属性 self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:self.launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:@"main" initialProperties:nil]; // 设置根视图背景色 if (@available(iOS 13.0, *)) { rootView.backgroundColor = [UIColor systemBackgroundColor]; } else { rootView.backgroundColor = [UIColor whiteColor]; } // 配置窗口与启动屏 UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; }
4. 修正启动流程中的重复代码
修改didFinishLaunchingWithOptions方法,移除重复的bridge和UIWindow创建逻辑:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RCTAppSetupPrepareApp(application); self.launchOptions = launchOptions; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; #if RCT_NEW_ARCH_ENABLED _contextContainer = std::make_shared<facebook::react::ContextContainer const>(); _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>(); _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); #endif #ifdef DEBUG [self initializeReactNativeApp]; #else EXUpdatesAppController *controller = [EXUpdatesAppController sharedInstance]; controller.delegate = self; [controller startAndShowLaunchScreen:self.window]; #endif return YES; }
5. 调整Debug环境初始化方法
修改initializeReactNativeApp,使用共享的bridge属性:
- (RCTBridge *)initializeReactNativeApp { self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:self.launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:@"main" initialProperties:nil]; if (@available(iOS 13.0, *)) { rootView.backgroundColor = [UIColor systemBackgroundColor]; } else { rootView.backgroundColor = [UIColor whiteColor]; } UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; return self.bridge; }
修复逻辑说明
- 遵守
EXUpdatesAppControllerDelegate协议并实现对应方法,直接解决unrecognized selector的崩溃问题,因为EXUpdatesAppController启动完成后会调用该代理方法通知结果。 - 移除重复的实例创建逻辑,保证Debug和Release环境的启动流程一致,避免资源冲突。
- 使用共享的
bridge属性,确保整个App生命周期内只有一个React Native实例,减少潜在的启动异常。
内容的提问来源于stack exchange,提问作者Exoriri
相关产品推荐
相关产品推荐

