📖 React Native 调用 Android、iOS 原生能力封装
1. 原理
React Native 的 核心思想:
-
JS 层(React 代码)不能直接调用 Android/iOS 的 API。
-
RN 提供了 Native Module 机制:
- Android :Java/Kotlin → 继承
ReactContextBaseJavaModule
,通过@ReactMethod
暴露方法。 - iOS :Objective-C/Swift → 使用
RCT_EXPORT_MODULE
和RCT_EXPORT_METHOD
暴露方法。
- Android :Java/Kotlin → 继承
-
JS 调用时通过
NativeModules
拿到对应的模块,再调用方法。 -
双向通信:
- JS → 原生(方法调用)
- 原生 → JS(事件通知 / 回调 Promise)
2. Android 封装原生能力
(1)新建原生 Module
java
// MyNativeModule.java
package com.myapp;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
public class MyNativeModule extends ReactContextBaseJavaModule {
MyNativeModule(ReactApplicationContext context) {
super(context);
}
@Override
public String getName() {
return "MyNative"; // JS 调用时用的名字
}
// 示例:获取电池电量
@ReactMethod
public void getBatteryLevel(Promise promise) {
try {
int battery = 80; // 假设写死,实际可用系统 API 获取
promise.resolve(battery);
} catch (Exception e) {
promise.reject("ERROR", e);
}
}
}
(2)注册 Module
java
// MyPackage.java
package com.myapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new MyNativeModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
在 MainApplication.java
里注册:
java
packages.add(new MyPackage());
3. iOS 封装原生能力
(1)Objective-C 示例
objc
// MyNativeModule.m
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(MyNative, NSObject)
RCT_EXTERN_METHOD(getBatteryLevel:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
@end
(2)Swift 示例
swift
@objc(MyNative)
class MyNative: NSObject {
@objc
func getBatteryLevel(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
let battery = 80 // 假设写死
resolve(battery)
}
}
4. JS 调用
tsx
import { NativeModules } from 'react-native';
const { MyNative } = NativeModules;
async function checkBattery() {
try {
const level = await MyNative.getBatteryLevel();
console.log("电池电量:", level);
} catch (e) {
console.error(e);
}
}
5. 原生 → JS 的事件通知
有些能力(如推送、传感器数据)需要原生主动回调 JS。
- Android :使用
DeviceEventManagerModule
java
WritableMap params = Arguments.createMap();
params.putString("event", "BatteryLow");
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("BatteryEvent", params);
- iOS :使用
RCTEventEmitter
objc
[self sendEventWithName:@"BatteryEvent" body:@{@"event": @"BatteryLow"}];
- JS 监听
tsx
import { NativeEventEmitter, NativeModules } from 'react-native';
const eventEmitter = new NativeEventEmitter(NativeModules.MyNative);
eventEmitter.addListener('BatteryEvent', (event) => {
console.log(event);
});
6. 最佳实践
-
模块化封装:
- 每个功能一个
Native Module
,按业务拆分。 - 统一放在
/native-modules/
目录下,JS 层再封装一层 API。
- 每个功能一个
-
跨平台统一接口:
- 在 JS 层写一个
Battery.ts
,内部判断Platform.OS
调用 Android/iOS 实现。
- 在 JS 层写一个
-
避免直接调用 NativeModules:
-
封装成业务方法,例如:
tsxexport async function getBatteryLevel(): Promise<number> { return await NativeModules.MyNative.getBatteryLevel(); }
-
-
新架构 TurboModules(进阶):
- 使用 JSI 直接绑定 C++ → JS 方法,无需 Bridge。
- 更高性能(避免 JSON 序列化)。
📌 总结:
RN 调用原生能力 = JS ↔ Native Module ↔ Android/iOS API
- JS 调用 Native:
NativeModules.MyNative.xxx()
- Native 调用 JS:事件/回调/Promise
- 封装要点:统一接口、模块化、尽量隐藏平台差异