React Native(RN)调用原生 Android/iOS 方法,以及原生回调 RN,核心机制是 Native Module(原生模块)+ Bridge/JSI 通信

整体流程:

        JavaScript (RN)
              |
              |
        Native Module 调用
              |
     ---------------------
     |                   |
 Android Native      iOS Native
 (Java/Kotlin)       (Obj-C/Swift)
     |                   |
     |                   |
 系统能力/API       系统能力/API

1. RN 调用 Android 原生方法

例如 RN 调用 Android 获取设备信息。

Android 创建 Module

Kotlin 示例:

class DeviceModule(
    reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {

    override fun getName(): String {
        return "DeviceModule"
    }

    @ReactMethod
    fun getDeviceName(promise: Promise) {

        val name = Build.MODEL

        promise.resolve(name)
    }
}

注册:

class MyPackage : ReactPackage {

    override fun createNativeModules(
        context: ReactApplicationContext
    ): List<NativeModule> {

        return listOf(
            DeviceModule(context)
        )
    }
}

加入:

packages.add(MyPackage())

2. RN JS 调用 Android

JS:

import {
 NativeModules
} from 'react-native';


const {DeviceModule} = NativeModules;


DeviceModule.getDeviceName()
.then(name=>{
    console.log(name)
});

调用链:

JS
 |
 | DeviceModule.getDeviceName()
 |
Bridge
 |
Android Module
 |
promise.resolve()
 |
Bridge
 |
JS Promise.then()

3. iOS 原生暴露方法给 RN

Swift 示例:

创建 Native Module

@objc(DeviceModule)
class DeviceModule: NSObject {


 @objc
 func getDeviceName(
    _ resolve:RCTPromiseResolveBlock,
    rejecter reject:RCTPromiseRejectBlock
 ){

    let name =
      UIDevice.current.name

    resolve(name)
 }


 @objc
 static func requiresMainQueueSetup()
 -> Bool {
    return false
 }

}

暴露:

#import <React/RCTBridgeModule.h>


@interface RCT_EXTERN_MODULE(
DeviceModule,
NSObject
)


RCT_EXTERN_METHOD(
getDeviceName:
resolver:(RCTPromiseResolveBlock)
rejecter:(RCTPromiseRejectBlock)
)

@end

RN 调用方式和 Android 一样:

DeviceModule.getDeviceName()
.then(console.log)

4. 原生主动回调 RN

例如:

  • 支付结果通知

  • 蓝牙扫描结果

  • GPS位置变化

  • 推送消息

  • 登录状态变化

这种不是 RN 调原生,而是:

Native
  |
  |
EventEmitter
  |
  |
React Native JS

Android 回调 RN

原生发送事件

reactContext
.getJSModule(
 DeviceEventManagerModule.RCTDeviceEventEmitter::class.java
)
.emit(
 "onLogin",
 "success"
)

JS监听

import {
 NativeEventEmitter,
 NativeModules
} from 'react-native';


const emitter =
new NativeEventEmitter(
 NativeModules.DeviceModule
);


const sub =
emitter.addListener(
 "onLogin",
 data=>{
    console.log(data)
 }
);

收到:

Android
 emit("onLogin")
        |
        |
 RN JS listener

5. iOS 回调 RN

Objective-C:

#import <React/RCTEventEmitter.h>


@interface DeviceModule:
RCTEventEmitter

@end

发送:

[self sendEventWithName:
 @"onLogin"
 body:@{
   @"status":@"success"
 }];

JS:

const emitter =
new NativeEventEmitter(
 NativeModules.DeviceModule
);


emitter.addListener(
"onLogin",
data=>{
 console.log(data)
});

6. Promise vs Callback vs Event

RN 原生通信常见三种:

方式 方向 场景
Promise JS → Native → JS 一次性结果
Callback JS → Native → JS 旧方式
EventEmitter Native → JS 持续事件

例如:

获取电量

Promise:

RN
 |
getBattery()
 |
Native
 |
return 80%

适合。


蓝牙扫描

Event:

Native

发现设备1
  |
emit

发现设备2
  |
emit

发现设备3

适合。


7. 新架构 Fabric / TurboModule 下

你之前问过 RN Fabric,这里关联:

旧架构:

JS
 |
Bridge(JSON)
 |
Native

性能瓶颈:

  • JSON序列化

  • 异步消息队列

新架构:

JS
 |
JSI
 |
C++层
 |
TurboModule
 |
Native

特点:

  • 不经过 JSON Bridge

  • 可以同步调用

  • 类型安全

  • 性能更高

例如:

旧:

NativeModules.Device.getName()

Bridge消息

新:

JS
 |
JSI Function
 |
C++
 |
Kotlin/Swift

8. 实际项目结构

比如微信扫码登录:

RN:

LoginModule.scanQRCode()

Native:

Android:

startCamera()
scan()

扫码成功:

emit(
"QRCodeResult",
{
 code:"abc123"
}
)

RN:

listener(
data=>{
 login(data.code)
}
)

流程:

RN点击登录
       |
       |
Native打开微信扫码
       |
       |
扫码完成
       |
       |
Native Event
       |
       |
RN收到code
       |
       |
请求服务器登录

所以 RN 和原生通信可以总结为:

RN调用原生:
NativeModules / TurboModule

原生返回一次:
Promise

原生持续通知:
EventEmitter

新架构:
JSI + TurboModule + Fabric

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐