name: native-module-helper description: 为iOS和Android创建自定义React Native原生模块。当集成原生SDK、优化性能关键代码或访问平台特定API时使用。触发词包括"原生模块"、“桥接”、“原生代码”、“iOS桥接”、“Android桥接”、“Turbo Module”。
Native Module Helper
构建自定义原生模块,以在React Native中桥接JavaScript和原生代码。
快速开始
原生模块将原生功能暴露给JavaScript。根据React Native版本选择:
- 旧版桥接: RN < 0.68(稳定,广泛支持)
- Turbo模块: RN >= 0.68(性能更好,类型安全)
说明
步骤1:规划模块接口
设计JavaScript API:
// 你想从JS中调用的
import { NativeModules } from 'react-native';
const { MyModule } = NativeModules;
// 同步
const result = MyModule.getValue();
// 异步(Promise)
const data = await MyModule.fetchData();
// 使用回调
MyModule.processData(input, (error, result) => {
if (error) console.error(error);
else console.log(result);
});
// 事件发射器
MyModule.addListener('onUpdate', (event) => {
console.log(event);
});
保持桥接调用最小化:
- 尽可能批量操作
- 避免频繁的小调用
- 使用事件进行连续更新
步骤2:创建模块结构
文件结构:
MyModule/
├── ios/
│ ├── MyModule.h
│ ├── MyModule.m(或.swift)
│ └── MyModule-Bridging-Header.h(如果使用Swift)
├── android/
│ └── src/main/java/com/mymodule/
│ ├── MyModulePackage.java
│ └── MyModule.java(或.kt)
├── js/
│ └── NativeMyModule.ts
└── package.json
步骤3:实现iOS模块
Objective-C(.h文件):
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface MyModule : RCTEventEmitter <RCTBridgeModule>
@end
Objective-C(.m文件):
#import "MyModule.h"
@implementation MyModule
RCT_EXPORT_MODULE();
// 同步方法
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getValue)
{
return @"value";
}
// 异步使用Promise
RCT_EXPORT_METHOD(fetchData:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
// 执行操作
if (success) {
resolve(@{@"data": result});
} else {
reject(@"ERROR_CODE", @"错误消息", error);
}
}
// 异步使用回调
RCT_EXPORT_METHOD(processData:(NSString *)input
callback:(RCTResponseSenderBlock)callback)
{
// 处理数据
callback(@[[NSNull null], result]); // [错误, 结果]
}
// 事件发射器
- (NSArray<NSString *> *)supportedEvents
{
return @[@"onUpdate"];
}
- (void)sendUpdate:(NSDictionary *)data
{
[self sendEventWithName:@"onUpdate" body:data];
}
@end
步骤4:实现Android模块
Java模块:
package com.mymodule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class MyModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
public MyModule(ReactApplicationContext context) {
super(context);
this.reactContext = context;
}
@Override
public String getName() {
return "MyModule";
}
// 同步方法
@ReactMethod(isBlockingSynchronousMethod = true)
public String getValue() {
return "value";
}
// 异步使用Promise
@ReactMethod
public void fetchData(Promise promise) {
try {
WritableMap result = Arguments.createMap();
result.putString("data", "value");
promise.resolve(result);
} catch (Exception e) {
promise.reject("ERROR_CODE", "错误消息", e);
}
}
// 异步使用回调
@ReactMethod
public void processData(String input, Callback callback) {
try {
String result = process(input);
callback.invoke(null, result); // 错误, 结果
} catch (Exception e) {
callback.invoke(e.getMessage(), null);
}
}
// 事件发射器
private void sendEvent(String eventName, WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
包注册:
package com.mymodule;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MyModulePackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new MyModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
步骤5:链接模块
自动链接(RN >= 0.60):
在模块根目录创建package.json:
{
"name": "react-native-my-module",
"version": "1.0.0",
"main": "js/index.js",
"react-native": "js/index.js"
}
手动链接(如果需要):
iOS:添加到Podfile
pod 'MyModule', :path => '../node_modules/react-native-my-module'
Android:添加到settings.gradle
include ':react-native-my-module'
project(':react-native-my-module').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-my-module/android')
步骤6:创建TypeScript接口
// js/NativeMyModule.ts
import { NativeModules, NativeEventEmitter } from 'react-native';
interface MyModuleInterface {
getValue(): string;
fetchData(): Promise<{ data: string }>;
processData(input: string, callback: (error: string | null, result: string | null) => void): void;
addListener(eventName: string, listener: (event: any) => void): void;
removeListeners(count: number): void;
}
const { MyModule } = NativeModules;
const eventEmitter = new NativeEventEmitter(MyModule);
export default MyModule as MyModuleInterface;
export { eventEmitter };
常见模式
线程处理
iOS(在后台线程上运行):
RCT_EXPORT_METHOD(heavyTask:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 繁重操作
NSString *result = [self performHeavyOperation];
dispatch_async(dispatch_get_main_queue(), ^{
resolve(result);
});
});
}
Android(在后台线程上运行):
@ReactMethod
public void heavyTask(Promise promise) {
new Thread(() -> {
try {
String result = performHeavyOperation();
promise.resolve(result);
} catch (Exception e) {
promise.reject("ERROR", e);
}
}).start();
}
数据类型转换
iOS:
// JS -> 原生
NSString *string = [RCTConvert NSString:value];
NSNumber *number = [RCTConvert NSNumber:value];
NSArray *array = [RCTConvert NSArray:value];
NSDictionary *dict = [RCTConvert NSDictionary:value];
// 原生 -> JS
return @{
@"string": @"value",
@"number": @(42),
@"array": @[@"a", @"b"],
@"dict": @{@"key": @"value"}
};
Android:
// JS -> 原生(自动)
String string = input;
int number = input;
ReadableArray array = input;
ReadableMap map = input;
// 原生 -> JS
WritableMap result = Arguments.createMap();
result.putString("string", "value");
result.putInt("number", 42);
WritableArray array = Arguments.createArray();
array.pushString("a");
array.pushString("b");
result.putArray("array", array);
错误处理
iOS:
RCT_EXPORT_METHOD(riskyOperation:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSError *error = nil;
id result = [self performOperation:&error];
if (error) {
reject(@"OPERATION_FAILED", error.localizedDescription, error);
} else {
resolve(result);
}
}
Android:
@ReactMethod
public void riskyOperation(Promise promise) {
try {
Object result = performOperation();
promise.resolve(result);
} catch (Exception e) {
promise.reject("OPERATION_FAILED", e.getMessage(), e);
}
}
高级
详细平台特定指南:
故障排除
找不到模块:
- 验证package.json配置
- 运行
pod install(iOS)或重新构建(Android) - 检查原生代码中的模块名称是否匹配
方法不可用:
- 确保使用RCT_EXPORT_METHOD
- 检查方法签名是否匹配
- 重新构建原生代码
调用方法时崩溃:
- 检查线程安全性
- 验证数据类型转换
- 添加空值检查
- 检查错误处理
未接收到事件:
- 验证supportedEvents(iOS)
- 检查事件发射器设置
- 确保在事件触发前添加监听器
最佳实践
- 最小化桥接调用:批量操作,使用事件进行更新
- 类型安全:使用TypeScript接口
- 错误处理:始终优雅地处理错误
- 线程处理:将繁重操作移出主线程
- 内存管理:清理资源,移除监听器
- 测试:在iOS和Android上测试
- 文档:清晰记录API
- 版本控制:使用语义化版本控制