由浅入深,从基本概念到源码解析,带你全面掌握 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/ios
pod 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 的演进,有助于在混合栈项目中做出更合适的架构与实现选择。