打破边界(一):实战编写 Android/iOS 原生模块 (Native Modules)

作为 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)
        }
    }
}

概念对比分析:

  1. ReactContextBaseJavaModule :相当于 Android 里的一个单例或 Service 类,它的生命周期绑定在 ReactContext 上。
  2. @ReactMethod :类似于 Android 中 WebView 的 @JavascriptInterface。它告诉 RN 框架,这个方法需要暴露给 JS 端。
  3. 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 了!

相关推荐
朱涛的自习室8 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
.Bryce.12 小时前
在智能体中使用A2A工具:让大模型自己决定“该找谁帮忙“
android·java·服务器·redis·后端·agent·a2a
看浪的路人13 小时前
第2讲:ReAct 模式从零实现——不用框架,手写一个 Agent 内核
前端·react.js·前端框架
方舟小孩13 小时前
开源办公软件海豹办公 1.9.15 实战 从模板异常到 Android WebView 资源回归
android
用户21816970493013 小时前
Kotlin 语法四 协程
android
出师牛13 小时前
Android - 再探Handler
android
高晶13 小时前
Android 物联网组网实战:NFC 从零到落地
android·java
stevenzqzq13 小时前
android 维度和渠道
android
古法安卓14 小时前
Android-SystemUI ANR协程相关问题排查
android·java·android studio
xiaogai_gai14 小时前
生产汇报单查询同步实战:从金蝶云星空拉取到轻易云数据集成平台的工程化做法
android