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

iOS生产构建启动崩溃:EXExpoAppDelegate收到未识别选择器

问题分析与修复方案

崩溃根源

这个启动崩溃的核心原因是:

  1. 生产环境中你设置了EXUpdatesAppController的代理为AppDelegate自身,但AppDelegate既未遵守EXUpdatesAppControllerDelegate协议,也未实现代理要求的appController:didStartWithSuccess:方法,导致系统调用不存在的方法抛出异常。
  2. 代码中存在重复初始化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:45:35