打破边界(一):实战编写 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.ktgetPackages() 列表中。

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 了!

相关推荐
武当王丶也35 分钟前
React Native 本地草稿设计:恢复、过期与版本迁移
react native
zttbee1 小时前
vue2的API大白话讲解
前端·vue.js·前端框架
baidu_247438611 小时前
Android 35适配
android
mmsx2 小时前
osmdroid 踩坑清单:大级别崩溃/路径消失/低内存卡顿/范围缩放不准
android·源码·地图·osmdroid
gf13211112 小时前
【python_回复邮件】
android·java·python
段一凡-华北理工大学3 小时前
高炉智能布料技术与炉料分布优化~专栏简介与目录
android·人工智能·高炉智能化·高炉布料·高炉布料分布·高炉布料参数优化·高炉布料矩阵
hunterandroid3 小时前
Android 多渠道打包与 Gradle 构建优化实战
android·前端·kotlin
小白羊丨3 小时前
异步任务创建接口如何幂等?
android·数据库