React Native原生模块 #

概述 #

当 React Native 没有提供某些功能时,可以通过原生模块来访问平台特有的 API。本章节介绍如何创建和使用原生模块。

iOS 原生模块 #

创建模块 #

  1. 创建 Objective-C 文件 RCTCalendarModule.h
objc
#import <React/RCTBridgeModule.h>

@interface RCTCalendarModule : NSObject <RCTBridgeModule>
@end
  1. 创建实现文件 RCTCalendarModule.m
objc
#import "RCTCalendarModule.h"

@implementation RCTCalendarModule

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(addEvent:(NSString *)name
                  location:(NSString *)location
                  date:(NSString *)date)
{
  NSLog(@"Add event: %@ at %@ on %@", name, location, date);
}

RCT_REMAP_METHOD(getEvents,
                 getEventsWithResolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
  NSArray *events = @[@"Event 1", @"Event 2", @"Event 3"];
  resolve(events);
}

@end

导出常量 #

objc
- (NSDictionary *)constantsToExport
{
  return @{ @"version": @"1.0.0" };
}

支持线程 #

objc
- (dispatch_queue_t)methodQueue
{
  return dispatch_get_main_queue();
}

Swift 原生模块 #

  1. 创建 Swift 文件 CalendarModule.swift
swift
import Foundation

@objc(CalendarModule)
class CalendarModule: NSObject {
  
  @objc
  func addEvent(_ name: String, location: String, date: String) {
    print("Add event: \(name) at \(location) on \(date)")
  }
  
  @objc
  func getEvents(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
    let events = ["Event 1", "Event 2", "Event 3"]
    resolve(events)
  }
  
  @objc
  static func requiresMainQueueSetup() -> Bool {
    return true
  }
}
  1. 创建桥接文件 CalendarModuleBridge.m
objc
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(CalendarModule, NSObject)

RCT_EXTERN_METHOD(addEvent:(NSString *)name
                  location:(NSString *)location
                  date:(NSString *)date)

RCT_EXTERN_METHOD(getEvents:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)

@end

Android 原生模块 #

创建模块 #

  1. 创建 Java 文件 CalendarModule.java
java
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;
import com.facebook.react.module.annotations.ReactModule;

@ReactModule(name = CalendarModule.NAME)
public class CalendarModule extends ReactContextBaseJavaModule {
  public static final String NAME = "CalendarModule";

  public CalendarModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return NAME;
  }

  @ReactMethod
  public void addEvent(String name, String location, String date) {
    System.out.println("Add event: " + name + " at " + location + " on " + date);
  }

  @ReactMethod
  public void getEvents(Promise promise) {
    try {
      WritableArray events = Arguments.createArray();
      events.pushString("Event 1");
      events.pushString("Event 2");
      events.pushString("Event 3");
      promise.resolve(events);
    } catch (Exception e) {
      promise.reject("ERROR", e.getMessage());
    }
  }
}

创建包 #

java
package com.myapp;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CalendarPackage implements ReactPackage {
  @Override
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    List<NativeModule> modules = new ArrayList<>();
    modules.add(new CalendarModule(reactContext));
    return modules;
  }

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Collections.emptyList();
  }
}

注册包 #

MainApplication.java 中:

java
@Override
protected List<ReactPackage> getPackages() {
  List<ReactPackage> packages = new PackageList(this).getPackages();
  packages.add(new CalendarPackage());
  return packages;
}

Kotlin 原生模块 #

kotlin
package com.myapp

import com.facebook.react.bridge.*
import com.facebook.react.module.annotations.ReactModule

@ReactModule(name = CalendarModule.NAME)
class CalendarModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
  
  companion object {
    const val NAME = "CalendarModule"
  }

  override fun getName(): String = NAME

  @ReactMethod
  fun addEvent(name: String, location: String, date: String) {
    println("Add event: $name at $location on $date")
  }

  @ReactMethod
  fun getEvents(promise: Promise) {
    try {
      val events = Arguments.createArray()
      events.pushString("Event 1")
      events.pushString("Event 2")
      events.pushString("Event 3")
      promise.resolve(events)
    } catch (e: Exception) {
      promise.reject("ERROR", e.message)
    }
  }
}

JavaScript 调用 #

基本调用 #

tsx
import {NativeModules} from 'react-native';

const {CalendarModule} = NativeModules;

const addEvent = async () => {
  CalendarModule.addEvent('Meeting', 'Office', '2024-01-15');
};

const getEvents = async () => {
  try {
    const events = await CalendarModule.getEvents();
    console.log('Events:', events);
  } catch (error) {
    console.error('Error:', error);
  }
};

TypeScript 类型定义 #

创建 NativeCalendarModule.ts

tsx
declare module 'react-native' {
  interface NativeModulesStatic {
    CalendarModule: {
      addEvent(name: string, location: string, date: string): void;
      getEvents(): Promise<string[]>;
      version: string;
    };
  }
}

事件发送 #

iOS 发送事件 #

objc
#import "CalendarModule.h"
#import <React/RCTEventEmitter.h>

@interface CalendarModule () <RCTEventEmitter>
@end

@implementation CalendarModule

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents {
  return @[@"onEventAdded"];
}

- (void)sendEventAdded:(NSString *)eventName {
  [self sendEventWithName:@"onEventAdded" body:@{@"name": eventName}];
}

@end

Android 发送事件 #

java
public class CalendarModule extends ReactContextBaseJavaModule {
  private static final String EVENT_NAME = "onEventAdded";

  public void sendEventAdded(String eventName) {
    ReactApplicationContext context = getReactApplicationContext();
    WritableMap params = Arguments.createMap();
    params.putString("name", eventName);
    context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
           .emit(EVENT_NAME, params);
  }
}

JavaScript 监听事件 #

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

const {CalendarModule} = NativeModules;
const eventEmitter = new NativeEventEmitter(CalendarModule);

useEffect(() => {
  const subscription = eventEmitter.addListener('onEventAdded', event => {
    console.log('Event added:', event.name);
  });

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

原生 UI 组件 #

iOS 原生视图 #

objc
#import <React/RCTViewManager.h>

@interface MyViewManager : RCTViewManager
@end

@implementation MyViewManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
  UILabel *label = [[UILabel alloc] init];
  label.text = @"Hello from native!";
  return label;
}

RCT_EXPORT_VIEW_PROPERTY(text, NSString)

@end

Android 原生视图 #

java
public class MyViewManager extends SimpleViewManager<TextView> {
  public static final String REACT_CLASS = "MyView";

  @Override
  public String getName() {
    return REACT_CLASS;
  }

  @Override
  protected TextView createViewInstance(ThemedReactContext reactContext) {
    TextView textView = new TextView(reactContext);
    textView.setText("Hello from native!");
    return textView;
  }

  @ReactProp(name = "text")
  public void setText(TextView view, String text) {
    view.setText(text);
  }
}

JavaScript 使用 #

tsx
import {requireNativeComponent} from 'react-native';

interface MyViewProps {
  text: string;
  style?: any;
}

const MyView = requireNativeComponent<MyViewProps>('MyView');

const App = () => {
  return <MyView text="Hello" style={{width: 200, height: 50}} />;
};

新架构:TurboModules #

概述 #

TurboModules 是 React Native 新架构的一部分,提供更好的类型安全和性能。

定义接口 #

创建 NativeCalendarModule.ts

typescript
export interface Spec extends TurboModule {
  addEvent(name: string, location: string, date: string): Promise<void>;
  getEvents(): Promise<string[]>;
  getConstants(): {
    version: string;
  };
}

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

Codegen 配置 #

package.json 中:

json
{
  "codegenConfig": {
    "name": "MyAppSpec",
    "type": "modules",
    "jsSrcsDir": "src/native"
  }
}

最佳实践 #

错误处理 #

tsx
const safeNativeCall = async <T>(
  nativeMethod: () => Promise<T>,
  fallback?: T,
): Promise<T | undefined> => {
  try {
    return await nativeMethod();
  } catch (error) {
    console.error('Native call failed:', error);
    return fallback;
  }
};

// 使用
const events = await safeNativeCall(
  () => CalendarModule.getEvents(),
  [],
);

平台检测 #

tsx
import {Platform, NativeModules} from 'react-native';

const getNativeModule = () => {
  if (Platform.OS === 'ios') {
    return NativeModules.IOSCalendarModule;
  } else {
    return NativeModules.AndroidCalendarModule;
  }
};

模块可用性检查 #

tsx
const isModuleAvailable = (moduleName: string): boolean => {
  return NativeModules[moduleName] !== undefined;
};

if (isModuleAvailable('CalendarModule')) {
  CalendarModule.getEvents();
} else {
  console.warn('CalendarModule not available');
}

总结 #

原生模块要点:

  • iOS:使用 Objective-C 或 Swift
  • Android:使用 Java 或 Kotlin
  • 导出方法:使用 RCT_EXPORT_METHOD / @ReactMethod
  • Promise:异步操作返回 Promise
  • 事件发送:使用 RCTEventEmitter
  • 原生视图:创建自定义 UI 组件
  • 新架构:使用 TurboModules

继续学习 性能优化,了解应用性能调优技巧。

最后更新:2026-03-28