【大前端】React Native 调用 Android、iOS 原生能力封装


📖 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_MODULERCT_EXPORT_METHOD 暴露方法。
  • 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. 最佳实践

  1. 模块化封装

    • 每个功能一个 Native Module,按业务拆分。
    • 统一放在 /native-modules/ 目录下,JS 层再封装一层 API。
  2. 跨平台统一接口

    • 在 JS 层写一个 Battery.ts,内部判断 Platform.OS 调用 Android/iOS 实现。
  3. 避免直接调用 NativeModules

    • 封装成业务方法,例如:

      tsx 复制代码
      export async function getBatteryLevel(): Promise<number> {
        return await NativeModules.MyNative.getBatteryLevel();
      }
  4. 新架构 TurboModules(进阶):

    • 使用 JSI 直接绑定 C++ → JS 方法,无需 Bridge。
    • 更高性能(避免 JSON 序列化)。

📌 总结:

RN 调用原生能力 = JS ↔ Native Module ↔ Android/iOS API

  • JS 调用 Native:NativeModules.MyNative.xxx()
  • Native 调用 JS:事件/回调/Promise
  • 封装要点:统一接口、模块化、尽量隐藏平台差异

相关推荐
stevenzqzq5 分钟前
android启动初始化和注入理解3
android
GIS之路7 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug10 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213812 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中34 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路37 分钟前
GDAL 实现矢量合并
前端
hxjhnct40 分钟前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端