作为 Android 开发者,我们经常需要调用底层的 API(如蓝牙、传感器、特定的 SDK 等)。在 React Native (RN) 中,当纯 JS 无法满足需求时,我们就需要编写 原生模块 (Native Modules) 。
本篇文章将带你了解如何在 RN 中编写原生模块,并与你熟悉的 Android/Kotlin 开发概念进行对比。
1. 原生模块的基本概念
在 RN 旧架构中,JS 与原生层的通信通过 Bridge(桥接) 进行,消息被序列化为 JSON 异步传递。这类似于 Android 中的 Handler 跨线程通信或者 IPC(进程间通信)。
在新架构(Turbo Native Modules / JSI)中,JS 可以直接持有 C++ 对象的引用并同步调用,类似于 JNI 的直接调用,性能大幅提升。不过,这里我们先从最经典的写法入手。
2. 编写 Android 原生模块
在 Android 侧,编写一个原生模块需要继承 ReactContextBaseJavaModule。
Kotlin vs JS 通信
在 Kotlin 中,我们这样定义一个模块:
kotlin
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
class MyCustomModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
// 必须重写 getName,这是 JS 端调用该模块的名称
override fun getName(): String {
return "MyCustomModule"
}
// 使用 @ReactMethod 暴露给 JS 的方法
@ReactMethod
fun doSomething(message: String, promise: Promise) {
try {
val result = "Android received: $message"
// 相当于 Kotlin Coroutines 的 resume 或是 callback 的 onSuccess
promise.resolve(result)
} catch (e: Exception) {
promise.reject("Error", e)
}
}
}
概念对比分析:
ReactContextBaseJavaModule:相当于 Android 里的一个单例或 Service 类,它的生命周期绑定在ReactContext上。@ReactMethod:类似于 Android 中 WebView 的@JavascriptInterface。它告诉 RN 框架,这个方法需要暴露给 JS 端。Promise:在 JS 端使用的是Promise。在 Android 侧传入com.facebook.react.bridge.Promise,它的resolve()和reject()就等价于我们在 Kotlin 协程中使用的Continuation.resume,或者常见的网络请求Callback.onSuccess/onError。
3. 注册模块
写完 Module 后,需要将其注册到 ReactPackage 中:
kotlin
class MyCustomPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(MyCustomModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
这类似于在 AndroidManifest.xml 中注册 Service 或者在 Dagger/Hilt 中提供 Module。最后将 MyCustomPackage 添加到 MainApplication.kt 的 getPackages() 列表中。
4. 在 JS 端调用
javascript
import { NativeModules } from 'react-native';
const { MyCustomModule } = NativeModules;
async function testModule() {
try {
const response = await MyCustomModule.doSomething("Hello from JS!");
console.log(response); // 输出: Android received: Hello from JS!
} catch (error) {
console.error(error);
}
}
5. 总结与进阶
- 同步 vs 异步 :默认情况下
@ReactMethod是异步的(运行在 Native Modules 线程,类似Dispatchers.IO)。如果你需要同步方法(阻塞 JS 线程),可以使用@ReactMethod(isBlockingSynchronousMethod = true),但要慎用,避免卡顿主线程。 - 事件发送 :如果 Android 需要主动给 JS 发消息(比如传感器数据流),可以使用
DeviceEventManagerModule.RCTDeviceEventEmitter。这就类似于 Android 中的EventBus或 Kotlin 的SharedFlow/BroadcastChannel。
掌握了原生模块的编写,你就可以在 RN 中随心所欲地调用任何 Android 原生 SDK 了!