React Native iOS仅Release构建时pushViewController报错
React Native iOS Release构建导航控制器类型不匹配问题
Debug构建正常,但切换到Release构建或使用eas build生成IPA时,调用原生模块openPendingAuthorization方法会抛出unrecognized selector sent to instance-pushviewcontrolleranimated错误——此时获取到的根视图控制器是普通ViewController而非预期的UINavigationController,Debug模式无此异常。
相关代码
AppDelegate.mm
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil]; rootView.backgroundColor = [UIColor whiteColor]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *reactViewController = [storyboard instantiateViewControllerWithIdentifier: @"ReactViewController"]; reactViewController.view = rootView; UINavigationController *navController = (UINavigationController*)[storyboard instantiateViewControllerWithIdentifier: @"UINavigationController"]; [navController pushViewController:viewController animated:YES]; self.navController = navController; self.window.rootViewController = navController; [self.window makeKeyAndVisible]; [super application:application didFinishLaunchingWithOptions:launchOptions]; return YES;
Homescreen.tsx
SdkModule.openPendingAuthorization( RAS_USER_ID, RAS_CLIENT_ID, RAS_CLIENT_SECRET, RAS_URL )
RCTSdkModule.m
RCT_EXPORT_METHOD(openPendingAuthorization:(NSString *)userId clientId:(NSString *)clientId clientSecret:(NSString *)clientSecret url:(NSString *)url) { Data *obj=[Data getInstance]; obj.userId = userId; obj.clientId = clientId; obj.clientSecret = clientSecret; obj.url = url; dispatch_async(dispatch_get_main_queue(), ^{ UIApplication *app = [UIApplication sharedApplication]; UINavigationController *nav = (UINavigationController *) app.delegate.window.rootViewController; UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier: @"SdkViewController"]; [nav pushViewController:viewController animated:YES]; }); }
SdkViewController.m
- (void)viewDidLoad { [super viewDidLoad]; // SDK Related Code }
解决方案
1. 增加类型校验,避免强制转换风险
在原生模块中获取根视图控制器时,先校验类型再执行操作,防止类型不匹配导致崩溃:
dispatch_async(dispatch_get_main_queue(), ^{ UIApplication *app = [UIApplication sharedApplication]; UIViewController *rootVC = app.delegate.window.rootViewController; UINavigationController *nav = nil; // 直接判断根VC是否为导航控制器 if ([rootVC isKindOfClass:[UINavigationController class]]) { nav = (UINavigationController *)rootVC; } // 检查是否是被present的导航控制器 else if (rootVC.presentedViewController && [rootVC.presentedViewController isKindOfClass:[UINavigationController class]]) { nav = (UINavigationController *)rootVC.presentedViewController; } // 若没有导航控制器,临时包裹一层 else { nav = [[UINavigationController alloc] initWithRootViewController:rootVC]; app.delegate.window.rootViewController = nav; [app.delegate.window makeKeyAndVisible]; } UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier: @"SdkViewController"]; [nav pushViewController:viewController animated:YES]; });
2. 优化导航控制器初始化方式
避免依赖故事板实例化导航控制器,直接代码创建可规避Release模式下的故事板加载异常:
// 替换AppDelegate中故事板实例化导航控制器的代码 // 注意:原代码中`viewController`未定义,需先实例化或替换为目标VC UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:reactViewController]; // 若需提前推入其他VC,确保viewController已正确实例化 // [navController pushViewController:viewController animated:YES]; self.navController = navController; self.window.rootViewController = navController;
3. 检查Release构建配置
- 确认
Dead Code Stripping选项在Release模式下未误移除导航控制器相关代码 - 验证
Main.storyboard已被正确添加到Release构建的资源包中
内容的提问来源于stack exchange,提问作者desertSniper87
相关产品推荐
相关产品推荐

