ReactNative原生模块Skill react-native-native-modules

此技能专注于在React Native框架中创建和集成原生模块,实现JavaScript与iOS/Android原生代码的桥接,支持Turbo Modules、平台特定API访问、原生事件处理和性能优化,关键词包括React Native、原生模块、Turbo Modules、iOS开发、Android开发、桥接技术、移动应用开发。

移动开发 0 次安装 0 次浏览 更新于 3/25/2026

名称: react-native-native-modules 用户可调用: false 描述: 在构建或集成React Native中的原生模块时使用。涵盖创建原生模块、Turbo Modules、桥接原生代码和访问平台特定API。 允许工具:

  • 读取
  • 写入
  • 编辑
  • Bash
  • Grep
  • Glob

React Native 原生模块

使用此技能当创建自定义原生模块、集成第三方原生库或访问通过JavaScript不可用的平台特定功能时。

关键概念

原生模块概述

原生模块桥接JavaScript和原生代码:

JavaScript层
      ↕ (桥接)
原生层 (iOS/Android)

Turbo Modules (现代方法)

Turbo Modules 提供更好的性能和类型安全:

// NativeMyModule.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  getString(value: string): Promise<string>;
  getNumber(value: number): number;
  getBoolean(value: boolean): boolean;
  getArray(value: Array<any>): Array<any>;
  getObject(value: Object): Object;
}

export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');

从JS调用原生代码

import { NativeModules } from 'react-native';

const { MyModule } = NativeModules;

// 调用原生方法
async function callNativeMethod() {
  try {
    const result = await MyModule.getString('Hello from JS');
    console.log(result);
  } catch (error) {
    console.error('原生模块错误:', error);
  }
}

最佳实践

iOS原生模块 (Swift)

在Swift中创建原生模块:

// MyModule.swift
import Foundation

@objc(MyModule)
class MyModule: NSObject {

  @objc
  func getString(_ value: String,
                 resolver: @escaping RCTPromiseResolveBlock,
                 rejecter: @escaping RCTPromiseRejectBlock) {
    // 处理值
    let result = "已处理: \(value)"
    resolver(result)
  }

  @objc
  func getNumber(_ value: NSNumber) -> NSNumber {
    let doubled = value.doubleValue * 2
    return NSNumber(value: doubled)
  }

  @objc
  static func requiresMainQueueSetup() -> Bool {
    return false
  }
}
// MyModule.m (桥接文件)
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(MyModule, NSObject)

RCT_EXTERN_METHOD(getString:(NSString *)value
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(getNumber:(nonnull NSNumber *)value)

@end

Android原生模块 (Kotlin)

在Kotlin中创建原生模块:

// MyModule.kt
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 MyModule(reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

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

    @ReactMethod
    fun getString(value: String, promise: Promise) {
        try {
            val result = "已处理: $value"
            promise.resolve(result)
        } catch (e: Exception) {
            promise.reject("ERROR", e.message)
        }
    }

    @ReactMethod
    fun getNumber(value: Double): Double {
        return value * 2
    }
}
// MyModulePackage.kt
package com.myapp

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

class MyModulePackage : ReactPackage {
    override fun createNativeModules(
        reactContext: ReactApplicationContext
    ): List<NativeModule> {
        return listOf(MyModule(reactContext))
    }

    override fun createViewManagers(
        reactContext: ReactApplicationContext
    ): List<ViewManager<*, *>> {
        return emptyList()
    }
}

TypeScript包装器

创建类型安全的包装器:

// MyModule.ts
import { NativeModules, Platform } from 'react-native';

interface MyModuleInterface {
  getString(value: string): Promise<string>;
  getNumber(value: number): number;
  getBoolean(value: boolean): boolean;
}

const LINKING_ERROR =
  `包 'react-native-my-module' 似乎未链接。请确保: 

` +
  Platform.select({ ios: "- 运行 'pod install'
", default: '' }) +
  '- 重新构建应用';

const MyModule: MyModuleInterface = NativeModules.MyModule
  ? NativeModules.MyModule
  : new Proxy(
      {},
      {
        get() {
          throw new Error(LINKING_ERROR);
        },
      }
    );

export default MyModule;

原生事件

从原生发送事件到JavaScript:

// iOS - MyModule.swift
import Foundation

@objc(MyModule)
class MyModule: RCTEventEmitter {

  override func supportedEvents() -> [String]! {
    return ["onDataReceived"]
  }

  @objc
  func startListening() {
    // 模拟接收数据
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
      self.sendEvent(withName: "onDataReceived",
                     body: ["data": "来自原生的问候!"])
    }
  }
}
// Android - MyModule.kt
class MyModule(reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

    private fun sendEvent(eventName: String, params: WritableMap?) {
        reactApplicationContext
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
            .emit(eventName, params)
    }

    @ReactMethod
    fun startListening() {
        val params = Arguments.createMap()
        params.putString("data", "来自原生的问候!")
        sendEvent("onDataReceived", params)
    }
}
// JavaScript
import { NativeEventEmitter, NativeModules } from 'react-native';
import { useEffect } from 'react';

function useNativeEvent() {
  useEffect(() => {
    const eventEmitter = new NativeEventEmitter(NativeModules.MyModule);

    const subscription = eventEmitter.addListener('onDataReceived', (event) => {
      console.log('从原生接收:', event.data);
    });

    NativeModules.MyModule.startListening();

    return () => subscription.remove();
  }, []);
}

常见模式

相机访问

// JavaScript API
interface CameraModule {
  takePicture(): Promise<string>; // 返回图片URI
  requestPermissions(): Promise<boolean>;
}
// iOS实现
import UIKit
import AVFoundation

@objc(CameraModule)
class CameraModule: NSObject {

  @objc
  func requestPermissions(_ resolve: @escaping RCTPromiseResolveBlock,
                         rejecter reject: @escaping RCTPromiseRejectBlock) {
    AVCaptureDevice.requestAccess(for: .video) { granted in
      resolve(granted)
    }
  }

  @objc
  func takePicture(_ resolve: @escaping RCTPromiseResolveBlock,
                   rejecter reject: @escaping RCTPromiseRejectBlock) {
    // 实现相机捕获
    // 返回图片URI
    resolve("file:///path/to/image.jpg")
  }
}
// Android实现
class CameraModule(reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

    @ReactMethod
    fun requestPermissions(promise: Promise) {
        // 检查和请求相机权限
        val hasPermission = ContextCompat.checkSelfPermission(
            reactApplicationContext,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED

        promise.resolve(hasPermission)
    }

    @ReactMethod
    fun takePicture(promise: Promise) {
        // 实现相机捕获
        promise.resolve("file:///path/to/image.jpg")
    }
}

生物识别认证

// JavaScript API
interface BiometricModule {
  authenticate(reason: string): Promise<{ success: boolean; error?: string }>;
  isAvailable(): Promise<boolean>;
}
// iOS实现
import LocalAuthentication

@objc(BiometricModule)
class BiometricModule: NSObject {

  @objc
  func isAvailable(_ resolve: @escaping RCTPromiseResolveBlock,
                   rejecter reject: @escaping RCTPromiseRejectBlock) {
    let context = LAContext()
    var error: NSError?

    let available = context.canEvaluatePolicy(
      .deviceOwnerAuthenticationWithBiometrics,
      error: &error
    )

    resolve(available)
  }

  @objc
  func authenticate(_ reason: String,
                   resolver resolve: @escaping RCTPromiseResolveBlock,
                   rejecter reject: @escaping RCTPromiseRejectBlock) {
    let context = LAContext()

    context.evaluatePolicy(
      .deviceOwnerAuthenticationWithBiometrics,
      localizedReason: reason
    ) { success, error in
      if success {
        resolve(["success": true])
      } else {
        resolve(["success": false, "error": error?.localizedDescription ?? ""])
      }
    }
  }
}

设备信息模块

// JavaScript API
interface DeviceInfoModule {
  getDeviceId(): string;
  getDeviceName(): string;
  getSystemVersion(): string;
  getBatteryLevel(): Promise<number>;
}
// iOS实现
import UIKit

@objc(DeviceInfoModule)
class DeviceInfoModule: NSObject {

  @objc
  func getDeviceId() -> String {
    return UIDevice.current.identifierForVendor?.uuidString ?? ""
  }

  @objc
  func getDeviceName() -> String {
    return UIDevice.current.name
  }

  @objc
  func getSystemVersion() -> String {
    return UIDevice.current.systemVersion
  }

  @objc
  func getBatteryLevel(_ resolve: @escaping RCTPromiseResolveBlock,
                       rejecter reject: @escaping RCTPromiseRejectBlock) {
    UIDevice.current.isBatteryMonitoringEnabled = true
    let level = UIDevice.current.batteryLevel
    resolve(level)
  }
}

原生UI组件

// 自定义原生视图
import { requireNativeComponent, ViewProps } from 'react-native';

interface MapViewProps extends ViewProps {
  region: {
    latitude: number;
    longitude: number;
    latitudeDelta: number;
    longitudeDelta: number;
  };
  onRegionChange?: (event: any) => void;
}

export const MapView = requireNativeComponent<MapViewProps>('MapView');

// 用法
<MapView
  region={{
    latitude: 37.78825,
    longitude: -122.4324,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
  }}
  onRegionChange={(event) => console.log(event.nativeEvent)}
/>

反模式

不要阻塞主线程

// 错误 - 阻塞主线程
@objc
func heavyComputation(_ value: String,
                     resolver resolve: @escaping RCTPromiseResolveBlock,
                     rejecter reject: @escaping RCTPromiseRejectBlock) {
  let result = performHeavyWork(value) // 阻塞UI
  resolve(result)
}

// 正确 - 使用后台线程
@objc
func heavyComputation(_ value: String,
                     resolver resolve: @escaping RCTPromiseResolveBlock,
                     rejecter reject: @escaping RCTPromiseRejectBlock) {
  DispatchQueue.global(qos: .userInitiated).async {
    let result = self.performHeavyWork(value)
    resolve(result)
  }
}

不要忘记错误处理

// 错误 - 无错误处理
@ReactMethod
fun readFile(path: String, promise: Promise) {
    val content = File(path).readText()
    promise.resolve(content)
}

// 正确 - 适当的错误处理
@ReactMethod
fun readFile(path: String, promise: Promise) {
    try {
        val file = File(path)
        if (!file.exists()) {
            promise.reject("FILE_NOT_FOUND", "文件不存在")
            return
        }
        val content = file.readText()
        promise.resolve(content)
    } catch (e: Exception) {
        promise.reject("READ_ERROR", e.message, e)
    }
}

不要泄漏内存

// 错误 - 强引用循环
class MyModule: NSObject {
    var timer: Timer?

    @objc
    func startTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
            self.doSomething() // 对self的强引用
        }
    }
}

// 正确 - 弱引用
class MyModule: NSObject {
    var timer: Timer?

    @objc
    func startTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.doSomething()
        }
    }

    deinit {
        timer?.invalidate()
    }
}

不要使用同步操作

// 错误 - 同步网络调用
@ReactMethod
fun fetchData(url: String): String {
    return URL(url).readText() // 阻塞线程
}

// 正确 - 异步与promise
@ReactMethod
fun fetchData(url: String, promise: Promise) {
    Thread {
        try {
            val data = URL(url).readText()
            promise.resolve(data)
        } catch (e: Exception) {
            promise.reject("FETCH_ERROR", e.message)
        }
    }.start()
}

相关技能

  • react-native-platform: 平台特定代码模式
  • react-native-components: 集成原生组件
  • react-native-performance: 原生性能优化