由浅入深,从基本概念到源码解析,带你全面掌握 React Native 在 iOS 平台的开发与应用
一、什么是 React Native?为什么选择它? 1.1 从 Hybrid 到 React Native 移动开发经历了从纯原生(Native)到 Hybrid(WebView)再到跨平台框架的演进:
方案
代表
优势
劣势
原生
Swift/ObjC
性能最佳、体验最好
双端重复开发
Hybrid
Cordova、WebView
一套 HTML/JS
性能差、体验割裂
跨平台
React Native、Flutter
一套代码、接近原生
学习曲线、生态依赖
React Native (RN) 由 Meta 于 2015 年开源,核心理念是:用 JavaScript 编写逻辑,用原生组件渲染 UI ,而不是在 WebView 中渲染。
1 2 传统 Hybrid: JS/HTML → WebView 渲染 → 间接调用原生 API React Native: JS/React → 虚拟 DOM → 原生组件(UILabel、UIView 等)直接渲染
1.2 为什么 iOS 开发者要学 React Native?
业务需要 :公司采用 RN 做跨端,需要维护/扩展原生能力
原生桥接 :RN 依赖大量原生模块(相机、蓝牙、支付等),需要 iOS 侧配合开发
性能优化 :理解 RN 与原生通信机制,才能做性能调优和问题排查
新架构 :新架构大量使用 C++、JSI,与 iOS 底层结合更紧密
1.3 RN 与 Flutter 的简要对比
维度
React Native
Flutter
语言
JavaScript/TypeScript
Dart
渲染
原生组件
自绘引擎(Skia)
包体积
相对较小
相对较大
生态
依赖 React、npm
独立生态
与原生交互
通过 Bridge/JSI
通过 Platform Channel
二、核心概念与架构 2.1 三层架构概览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ┌─────────────────────────────────────────────────────────┐ │ JavaScript 层 │ │ React 组件、业务逻辑、状态管理、事件处理 │ └──────────────────────────┬──────────────────────────────┘ │ Bridge / JSI ┌──────────────────────────▼──────────────────────────────┐ │ C++ 层(新架构) │ │ JSI、Fabric 渲染、TurboModules 调度 │ └──────────────────────────┬──────────────────────────────┘ │ FFI / Objective-C++ ┌──────────────────────────▼──────────────────────────────┐ │ Native 层(iOS) │ │ UIKit、系统 API、自定义原生模块 │ └─────────────────────────────────────────────────────────┘
2.2 关键概念
概念
说明
Bridge
旧架构中 JS 与 Native 的异步通信桥梁,数据需序列化
JSI
JavaScript Interface,新架构中 JS 可直接持有 C++ 对象引用,同步调用
Fabric
新架构的渲染系统,将布局、绘制逻辑下沉到 C++
TurboModules
新架构的原生模块系统,懒加载、类型安全
Hermes
字节码引擎,替代 JavaScriptCore,提升启动与运行性能
2.3 旧架构 vs 新架构
维度
旧架构
新架构
通信
Bridge 异步、JSON 序列化
JSI 同步、直接引用
渲染
各平台各自实现
Fabric 统一 C++ 渲染管线
原生模块
Native Modules 启动时全量加载
TurboModules 按需懒加载
类型
无强类型约定
通过 Codegen 生成类型
三、环境搭建与项目创建 3.1 环境要求
Node.js :建议 LTS 版本(18+)
Xcode :最新稳定版
CocoaPods :gem install cocoapods
Watchman (可选):brew install watchman,用于文件监听
3.2 创建新项目 1 2 3 4 5 6 7 8 9 10 11 npx @react-native-community/cli init MyApp cd MyApp/iospod install cd .. && npx react-native start
另开终端运行 iOS:
1 2 3 npx react-native run-ios npx react-native run-ios --simulator="iPhone 15"
3.3 项目结构(iOS 侧) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 MyApp/ ├── ios/ │ ├── MyApp/ # 原生 iOS 工程 │ │ ├── AppDelegate.mm # 入口,加载 RN 根视图 │ │ ├── Info.plist │ │ └── ... │ ├── Podfile # CocoaPods 配置 │ ├── Podfile.lock │ └── MyApp.xcworkspace # 用此打开工程 ├── android/ ├── src/ # JS 源码 ├── node_modules/ ├── package.json └── metro.config.js
3.4 AppDelegate 与 RN 加载 典型的 AppDelegate.mm 中加载 RN 的流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> - (BOOL )application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" ]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"MyApp" initialProperties:nil launchOptions:launchOptions]; self .window.rootViewController = [[UIViewController alloc] init]; self .window.rootViewController.view = rootView; [self .window makeKeyAndVisible]; return YES ; }
RCTRootView 负责加载 JS Bundle、创建 Bridge、挂载 React 组件树。
四、JS 与 Native 通信原理 4.1 旧架构:Bridge 模型 旧架构下,JS 与 Native 通过 异步 Bridge 通信:
1 2 3 4 5 6 7 JS 层发起调用 │ ├─ 将参数序列化为 JSON │ ├─ 通过 Bridge 发送到 Native 队列 │ └─ Native 解析 JSON,执行对应模块方法,再序列化结果回传 JS
特点 :
异步:所有跨端调用都是异步的
序列化:参数和返回值需要 JSON 序列化,有性能开销
全量加载:所有 Native Modules 在启动时注册
4.2 旧架构模块注册流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @interface MyNativeModule : NSObject <RCTBridgeModule >@end @implementation MyNativeModule RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(getDeviceId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { NSString *id = [[UIDevice currentDevice] identifierForVendor].UUIDString; resolve(id ); } @end
JS 端调用:
1 2 3 4 import { NativeModules } from 'react-native' ;const { MyNativeModule } = NativeModules ;const id = await MyNativeModule .getDeviceId ();
4.3 新架构:JSI 直接调用 JSI 允许 JavaScript 直接持有 C++ 对象的引用 ,无需经过 Bridge 序列化:
1 2 3 4 5 6 7 8 jsi::Function getDeviceId = jsi::Function::createFromHostFunction ( runtime, jsi::PropNameID::forAscii(runtime, "getDeviceId" ), 0 , [](jsi::Runtime& rt, const jsi::Value&, const jsi::Value*, size_t ) { return jsi::String::createFromUtf8 (rt, getNativeDeviceId ()); });
JS 可直接同步调用,无需 Promise 包装。
五、新架构:JSI、Fabric、TurboModules 5.1 JSI(JavaScript Interface) JSI 是 C++ 实现的薄封装层,让 JS 引擎(Hermes/JSC)能够:
调用 C++ 函数
读取/写入 C++ 对象属性
在 C++ 中执行 JS 回调
1 2 3 4 5 6 7 8 9 class DeviceModule : public jsi::HostObject { jsi::Value get (jsi::Runtime& rt, const jsi::PropNameID& name) override { if (name.utf8 (rt) == "getDeviceId" ) { return jsi::Function::createFromHostFunction (...); } return jsi::Value::undefined (); } };
5.2 Fabric 渲染管线 Fabric 将 React 的渲染逻辑从各平台分别实现,统一到 C++:
1 2 3 4 5 6 7 8 9 10 11 12 13 React 组件树 │ ▼ Shadow Tree(C++ 中的布局树) │ ▼ 布局计算(Yoga) │ ▼ 提交到原生层(Mount) │ ▼ iOS UIView 创建/更新
优势:减少跨 Bridge 的序列化、支持同步布局、更好的并发与优先级调度。
5.3 TurboModules TurboModules 的特性:
懒加载 :只在首次被 JS 引用时初始化
类型安全 :通过 Codegen 从 TypeScript 定义生成 C++ 和 ObjC 代码
同步能力 :通过 JSI 可实现同步调用
定义原生模块的规范(新架构):
1 2 3 4 5 6 7 8 9 10 import type { TurboModule } from 'react-native' ;import { TurboModuleRegistry } from 'react-native' ;export interface Spec extends TurboModule { getDeviceId (): Promise <string >; multiply (a : number , b : number ): number ; } export default TurboModuleRegistry .getEnforcing <Spec >('MyNativeModule' );
六、原生模块开发(Native Modules) 6.1 旧架构:RCT_EXPORT_MODULE 完整示例:实现一个获取设备信息的原生模块。
Objective-C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #import <React/RCTBridgeModule.h> @interface DeviceInfoModule : NSObject <RCTBridgeModule >@end #import "DeviceInfoModule.h" #import <React/RCTLog.h> #import <UIKit/UIKit.h> @implementation DeviceInfoModule RCT_EXPORT_MODULE(DeviceInfo) RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { dispatch_async (dispatch_get_main_queue(), ^{ NSDictionary *info = @{ @"model" : [[UIDevice currentDevice] model], @"systemVersion" : [[UIDevice currentDevice] systemVersion], @"name" : [[UIDevice currentDevice] name], }; resolve(info); }); } @end
JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 import { NativeModules } from 'react-native' ;const { DeviceInfo } = NativeModules ;async function loadDeviceInfo ( ) { try { const info = await DeviceInfo .getDeviceInfo (); console .log (info); } catch (e) { console .error (e); } }
6.2 新架构:TurboModule + Swift 新架构推荐用 Swift 实现业务逻辑 ,用 ObjC++ 做 JSI 胶水层。
Swift 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import Foundation@objc(DeviceInfoModule) class DeviceInfoModule : NSObject { @objc static func requiresMainQueueSetup () -> Bool { return false } @objc func getDeviceInfo (_ resolve : @escaping RCTPromiseResolveBlock , reject : @escaping RCTPromiseRejectBlock ) { let info: [String : Any ] = [ "model" : UIDevice .current.model, "systemVersion" : UIDevice .current.systemVersion ] resolve(info) } }
通过 RCT_EXTERN_MODULE 导出给 ObjC:
1 2 3 4 5 6 7 8 9 #import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE (DeviceInfoModule , NSObject )RCT_EXTERN_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) @end
6.3 事件发送:从 Native 到 JS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #import <React/RCTEventEmitter.h> @interface MyModule : RCTEventEmitter <RCTBridgeModule >@end @implementation MyModule RCT_EXPORT_MODULE() - (NSArray <NSString *> *)supportedEvents { return @[@"onScanResult" ]; } - (void )sendScanResult:(NSString *)result { [self sendEventWithName:@"onScanResult" body:@{@"result" : result}]; } @end
1 2 3 4 5 6 import { NativeEventEmitter , NativeModules } from 'react-native' ;const emitter = new NativeEventEmitter (NativeModules .MyModule );emitter.addListener ('onScanResult' , (event ) => { console .log (event.result ); });
七、原生 UI 组件(Native UI Components) 7.1 使用 ViewManager 封装 UIView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #import <React/RCTViewManager.h> @interface MyCustomViewManager : RCTViewManager @end #import "MyCustomViewManager.h" #import "MyCustomView.h" @implementation MyCustomViewManager RCT_EXPORT_MODULE(MyCustomView) - (UIView *)view { return [[MyCustomView alloc] init]; } RCT_EXPORT_VIEW_PROPERTY(title, NSString ) RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock) @end
1 2 3 4 5 @interface MyCustomView : UIView @property (nonatomic , copy ) NSString *title;@property (nonatomic , copy ) RCTBubblingEventBlock onPress;@end
7.2 JS 侧使用 1 2 3 4 5 6 7 8 9 10 11 12 import { requireNativeComponent } from 'react-native' ;const MyCustomView = requireNativeComponent ('MyCustomView' );export default function Screen ( ) { return ( <MyCustomView title ="Hello" onPress ={(e) => console.log(e.nativeEvent)} /> ); }
7.3 新架构:Fabric 组件 新架构下,通过 Codegen 定义 Props 和事件,生成 C++ 与各平台代码,实现类型安全和更好的性能。
八、源码解析 8.1 初始化流程(iOS) 1 2 3 4 5 6 7 8 9 10 11 12 main() └─ UIApplicationMain └─ AppDelegate didFinishLaunchingWithOptions └─ RCTRootView initWithBundleURL:moduleName:... ├─ 创建 RCTBridge │ ├─ 加载 JavaScript Bundle │ ├─ 初始化 JS 引擎(Hermes/JSC) │ ├─ 注册所有 Native Modules │ └─ 执行 JS 入口(AppRegistry.runApplication) │ └─ 创建 RCTRootContentView └─ 挂载 React 根组件,触发首次渲染
8.2 Bridge 核心结构(旧架构) 1 2 3 4 5 6 7 8 9 10 11 12 @interface RCTBridge : NSObject @property (nonatomic , strong ) RCTBridge *batchedBridge; @end
8.3 新架构关键路径
JSI :ReactCommon/jsi/,提供 jsi::Runtime、HostObject 等
Fabric :ReactCommon/react/renderer/,Shadow Tree、Mount、Component 定义
TurboModules :ReactCommon/react/nativemodule/,模块注册与调用
可参考官方仓库:https://github.com/facebook/react-native
九、实战示例 9.1 调用系统分享 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 RCT_EXPORT_METHOD(share:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { dispatch_async (dispatch_get_main_queue(), ^{ NSString *title = options[@"title" ] ?: @"" ; NSString *url = options[@"url" ] ?: @"" ; UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[title, [NSURL URLWithString:url]] applicationActivities:nil ]; UIViewController *rootVC = [UIApplication sharedApplication] .keyWindow.rootViewController; [rootVC presentViewController:activityVC animated:YES completion:nil ]; resolve(@YES); }); }
9.2 封装原生 TabBar 在 RN 中嵌入 UITabBarController 的容器,通过 Native Module 控制 Tab 切换,实现与原生 TabBar 一致的外观和动效。
9.3 列表性能优化:FlashList 1 2 3 4 5 6 7 8 9 10 11 12 13 import { FlashList } from '@shopify/flash-list' ;function ProductList ({ data } ) { const renderItem = ({ item } ) => <ProductCard item ={item} /> ; return ( <FlashList data ={data} renderItem ={renderItem} estimatedItemSize ={100} /> ); }
FlashList 使用按需渲染和复用,比 FlatList 更适合长列表场景。
十、实际项目中的应用案例 10.1 电商 App:商品详情混合栈
Native :顶部 Banner 轮播、视频播放、复杂动效
RN :评价列表、推荐列表、加购/下单逻辑
通过 RCTRootView 嵌入到 UIViewController 的指定区域,实现「上原生、下 RN」的混合页面。
10.2 金融 App:安全键盘 输入密码时使用 Native 自定义键盘(避免 RN 侧键盘被截屏/录屏),通过 Native Module 将输入结果回传 JS:
1 2 3 4 5 6 7 8 RCT_EXPORT_METHOD(showSecureKeyboard:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { SecureKeyboardViewController *vc = [[SecureKeyboardViewController alloc] initWithCompletion:^(NSString *pin) { resolve(pin); }]; [self presentVC:vc]; }
10.3 地图与 LBS 地图、路径规划、定位等使用 Native SDK,通过 Native UI Component 和 Native Module 暴露给 RN,兼顾性能与功能完整性。
10.4 OTA 热更新 将打包好的 JS Bundle 下发到本地,启动时优先加载本地 Bundle,实现不发版即可更新业务逻辑(需注意各应用市场的合规要求)。
十一、常见问题与最佳实践 11.1 主线程与 UI 更新 原生模块中涉及 UI 的操作必须回到主线程:
1 2 3 dispatch_async (dispatch_get_main_queue(), ^{ [self presentViewController:vc animated:YES completion:nil ]; });
11.2 避免内存泄漏
使用 RCTEventEmitter 时正确实现 invalidate
Block 中使用 weakSelf 避免循环引用
大对象及时释放,避免长期持有
11.3 调试技巧 1 2 3 4 5 6 7 8 npx react-native start npx react-native run-ios --device
11.4 性能建议
长列表使用 FlashList 或优化 FlatList 的 getItemLayout
复杂动画考虑 react-native-reanimated
新项目尽量启用新架构(Fabric + TurboModules)
图片使用 FastImage 或自定义 Native 图片组件做缓存
11.5 启用新架构 在 ios/Podfile 中:
1 ENV ['RCT_NEW_ARCH_ENABLED' ] = '1'
执行 pod install 后重新编译。
十二、总结
场景
建议
新项目
启用新架构(Fabric + TurboModules + Hermes)
原生能力扩展
通过 Native Module 暴露,优先用 Swift + ObjC 桥接
复杂 UI
封装 Native UI Component,或使用成熟第三方组件
性能敏感
长列表用 FlashList,动画用 Reanimated
调试
Metro + Flipper + Xcode 结合使用
React Native 在 iOS 上的核心价值是:用 React 生态统一业务逻辑,用原生能力保证体验与性能 。理解 Bridge/JSI、Fabric、TurboModules 的演进,有助于在混合栈项目中做出更合适的架构与实现选择。