一、先把「RN Bridge 是什么」想明白(非常關(guān)鍵)
1?? 流程
JS 線程(業(yè)務(wù)邏輯)
↓
Bridge(消息通道)
↓
Native 線程(iOS / Android)
↓
UI / 系統(tǒng)能力
重點(diǎn)一句話:
JS 和 iOS 不能直接互相調(diào)用方法,只能“發(fā)消息”
2?? RN Bridge 本質(zhì)是什么?
?? 一個(gè)異步的消息總線
消息里包含:
? 模塊名
? 方法名
? 參數(shù)(JSON)
? 回調(diào) / Promise 標(biāo)識(shí)
它不是函數(shù)調(diào)用,是“RPC”
3?? RN Bridge 能干什么 / 不能干什么
? 適合
? 調(diào)系統(tǒng)能力(相機(jī)、相冊(cè)、支付)
? 調(diào)原生 SDK
? 狀態(tài)通知(登錄成功、播放狀態(tài))
? 不適合
? 高頻調(diào)用(滾動(dòng)、動(dòng)畫(huà))
? 同步返回值
? 傳大對(duì)象 / 二進(jìn)制
二、最基礎(chǔ):JS 調(diào) iOS(無(wú)返回值)
Step 1:創(chuàng)建一個(gè) iOS 原生模塊
1?? 新建 OC 文件
ios/
└── DeviceModule.h
└── DeviceModule.m
2?? .h 文件
#import <React/RCTBridgeModule.h>
@interface DeviceModule : NSObject <RCTBridgeModule>
@end
?? 你在這里做了 2 件事:
? 引入 RN Bridge 協(xié)議
? 告訴 RN:這是個(gè)可被 JS 訪問(wèn)的模塊
3?? .m 文件(最關(guān)鍵)
#import "DeviceModule.h"
@implementation DeviceModule
RCT_EXPORT_MODULE(DeviceModule); //模塊名
RCT_EXPORT_METHOD(log:(NSString *)msg) { //方法名 和 參數(shù)(JSON)
NSLog(@"來(lái)自 RN 的消息:%@", msg);
}
@end
Step 2:JS 側(cè)調(diào)用
import { NativeModules } from 'react-native';
NativeModules.DeviceModule.log('Hello iOS');
流程
JS
↓
NativeModules.DeviceModule.log
↓
Bridge
↓
DeviceModule.m
Step 3:常見(jiàn)新手坑
? 方法寫(xiě)成實(shí)例方法沒(méi)問(wèn)題
? 但 不能有返回值
// ? 錯(cuò)
RCT_EXPORT_METHOD(getName) {
return @"abc";
}
三、JS 調(diào) iOS(帶返回值)
RN 不能同步 return,只能:
? callback
? Promise(強(qiáng)烈推薦)
方式一:Callback(不推薦)
iOS
RCT_EXPORT_METHOD(getDeviceName:(RCTResponseSenderBlock)callback) {
callback(@[@"iPhone 15"]);
}
JS
NativeModules.DeviceModule.getDeviceName(name => {
console.log(name);
});
? 問(wèn)題:
? 易回調(diào)地獄
? 錯(cuò)誤處理不清晰
方式二:Promise(你以后 90% 用這個(gè))
iOS
RCT_EXPORT_METHOD(getDeviceName:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
resolve(@"iPhone");
}
JS
const name = await NativeModules.DeviceModule.getDeviceName();
?? Promise 的規(guī)則
? resolve:成功
? reject:失敗
? JS 側(cè)可以 try/catch
四、JS ? iOS 參數(shù)支持哪些類(lèi)型?
? 支持(JSON 能表示的)

五、iOS 主線程 & 后臺(tái)線程(很容易卡)
默認(rèn)行為
RCT_EXPORT_METHOD(doSomething) {
// 默認(rèn)在 **子線程**
}
如果你要更新 UI(必須主線程)
RCT_EXPORT_METHOD(showAlert) {
dispatch_async(dispatch_get_main_queue(), ^{
// UI 操作
});
}
或者直接聲明
Objc 代碼
+ (BOOL)requiresMainQueueSetup {
return YES;
}
?? 適合:
? 初始化 UIKit
? SDK 依賴(lài)主線程
六、Native 主動(dòng)通知 RN(事件機(jī)制)
這是 第二大核心能力
Step 1:繼承 RCTEventEmitter
#import <React/RCTEventEmitter.h>
@interface EventModule : RCTEventEmitter
@end
Step 2:聲明事件名
- (NSArray<NSString *> *)supportedEvents {
return @[@"LoginSuccess"];
}
Step 3:發(fā)送事件
[self sendEventWithName:@"LoginSuccess"
body:@{@"uid": @"123"}];
Step 4:JS 監(jiān)聽(tīng)
import { NativeEventEmitter, NativeModules } from 'react-native';
const emitter = new NativeEventEmitter(NativeModules.EventModule);
emitter.addListener('LoginSuccess', data => {
console.log(data.uid);
});
七、生命周期 & 常見(jiàn)使用場(chǎng)景

八、你現(xiàn)在就能寫(xiě)一個(gè)“合格”的橋接模塊了
最小模板(可直接復(fù)用)
@interface XXXModule : NSObject <RCTBridgeModule>
@end
@implementation XXXModule
RCT_EXPORT_MODULE
RCT_EXPORT_METHOD(action:(NSDictionary *)params
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
resolve(@{@"success": @YES});
}
@end
swift使用











十、最小可復(fù)制模板(你可以直接存下來(lái))
Swift
@objc(DeviceModule)
class DeviceModule: NSObject {
@objc
func action(
_ params: NSDictionary,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock
) {
resolve(["success": true])
}
}
OC Bridge
@interface RCT_EXTERN_MODULE(DeviceModule, NSObject)
RCT_EXTERN_METHOD(
action:(NSDictionary *)params
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject
)
@end