插件开发
React Native 原生插件开发全解析
React Native 原生插件开发是连接 JavaScript 与原生平台(Android/iOS)的关键技术,能够让你利用原生 API 实现高性能功能。以下从核心概念到实战步骤全面解析原生插件开发。
一、核心概念与架构
1. 插件架构
React Native 原生插件采用双向通信架构:
- JavaScript 层:通过
NativeModules调用原生功能。 - 桥接层:CatalystInstance 负责 JS 与原生的消息传递。
- 原生层:实现具体平台功能(Java/Kotlin 或 Objective-C/Swift)。
2. 通信机制
- 异步调用:大多数原生方法通过消息队列异步调用。
- 同步调用:通过 TurboModules 支持同步调用(仅限新架构)。
二、Android 原生插件开发
1. 创建原生模块
// MyNativeModule.java
package com.myplugin;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
public class MyNativeModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
public MyNativeModule(ReactApplicationContext context) {
super(context);
this.reactContext = context;
}
@Override
public String getName() {
return "MyNativeModule"; // JS 中通过 NativeModules.MyNativeModule 访问
}
// 异步方法(带 Promise)
@ReactMethod
public void getDeviceInfo(Promise promise) {
try {
WritableMap result = Arguments.createMap();
result.putString("model", Build.MODEL);
result.putString("version", Build.VERSION.RELEASE);
promise.resolve(result);
} catch (Exception e) {
promise.reject("ERROR", e.getMessage());
}
}
// 同步方法(仅限新架构 TurboModules)
@ReactMethod(isBlockingSynchronousMethod = true)
public String getAppName() {
return reactContext.getPackageName();
}
}
2. 创建包(Package)
// MyPackage.java
package com.myplugin;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new MyNativeModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList(); // 若有自定义视图管理器,在此添加
}
}
3. 注册包
// MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.asList(
new MainReactPackage(),
new MyPackage() // 注册自定义包
);
}
三、iOS 原生插件开发
1. 创建 Objective-C 模块
// RNMyNativeModule.h
#import <React/RCTBridgeModule.h>
@interface RNMyNativeModule : NSObject <RCTBridgeModule>
@end
// RNMyNativeModule.m
#import "RNMyNativeModule.h"
@implementation RNMyNativeModule
RCT_EXPORT_MODULE(MyNativeModule); // JS 中通过 NativeModules.MyNativeModule 访问
// 异步方法
RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString *model = [UIDevice currentDevice].model;
NSString *version = [UIDevice currentDevice].systemVersion;
resolve(@{@"model": model, @"version": version});
}
// 同步方法(仅限新架构)
RCT_REMAP_METHOD(getAppName,
getAppNameWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
resolve([[NSBundle mainBundle] bundleIdentifier]);
}
@end
2. Swift 模块开发
// RNMyNativeModule.swift
import Foundation
import React
@objc(RNMyNativeModule)
class RNMyNativeModule: NSObject, RCTBridgeModule {
static func moduleName() -> String! {
return "MyNativeModule"
}
static func requiresMainQueueSetup() -> Bool {
return true
}
@objc func getDeviceInfo(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
let device = UIDevice.current
let info = [
"model": device.model,
"version": device.systemVersion
]
resolve(info)
}
@objc func getAppName(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
resolve(Bundle.main.bundleIdentifier)
}
}
四、JavaScript 接口封装
创建 JavaScript 包装层,简化原生模块调用:
// MyNativeModule.js
import { NativeModules, NativeEventEmitter } from 'react-native';
const { MyNativeModule } = NativeModules;
// 确保模块存在
if (!MyNativeModule) {
console.warn('MyNativeModule 未正确加载');
}
export const getDeviceInfo = async () => {
if (!MyNativeModule) return null;
return MyNativeModule.getDeviceInfo();
};
export const getAppName = () => {
if (!MyNativeModule) return null;
return MyNativeModule.getAppName();
};
// 事件监听(如果原生模块发送事件)
const eventEmitter = new NativeEventEmitter(MyNativeModule);
export const addListener = (eventName, callback) => {
return eventEmitter.addListener(eventName, callback);
};
五、自定义视图组件开发
1. Android 端视图管理器
// MyCustomViewManager.java
public class MyCustomViewManager extends SimpleViewManager<MyCustomView> {
public static final String REACT_CLASS = "MyCustomView";
@Override
public String getName() {
return REACT_CLASS;
}
@Override
protected MyCustomView createViewInstance(ThemedReactContext reactContext) {
return new MyCustomView(reactContext);
}
// 设置属性
@ReactProp(name = "color")
public void setColor(MyCustomView view, @Nullable String color) {
view.setColor(color);
}
}
2. iOS 端视图管理器
// RNMyCustomViewManager.h
#import <React/RCTViewManager.h>
@interface RNMyCustomViewManager : RCTViewManager
@end
// RNMyCustomViewManager.m
#import "RNMyCustomViewManager.h"
#import "MyCustomView.h"
@implementation RNMyCustomViewManager
RCT_EXPORT_MODULE(MyCustomView);
- (UIView *)view {
return [[MyCustomView alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
@end
3. JavaScript 组件封装
// MyCustomView.js
import { requireNativeComponent } from 'react-native';
const MyCustomView = requireNativeComponent('MyCustomView');
export default MyCustomView;
六、调试与发布
1. 调试技巧
- Android:使用 Android Studio 断点调试原生代码。
- iOS:在 Xcode 中调试 Swift/Objective-C 代码。
- JS 与原生通信:通过 Chrome DevTools 监控消息队列。
2. 发布到 npm
- 创建
package.json定义插件信息。 - 添加文档说明使用方法。
- 发布到 npm:
npm publish
七、新架构(Fabric & TurboModules)适配
1. TurboModules 改造
// TurboModule 实现(Android)
public class MyTurboModule extends ReactContextBaseJavaModule implements TurboModule {
// 实现方法
}
2. Fabric 视图组件
// Fabric 视图组件(Android)
public class MyFabricViewManager extends ViewManager<MyView, MyShadowNode> {
// 实现 Fabric 相关方法
}
八、注意事项
-
线程安全:
- 避免在 UI 线程执行耗时操作。
- 使用
runOnUiThread(Android)或DispatchQueue(iOS)切换线程。
-
内存管理:
- 避免内存泄漏,及时释放资源。
- 在
onCatalystInstanceDestroy()中清理资源。
-
版本兼容:
- 测试不同 React Native 版本的兼容性。
- 使用条件编译处理版本差异。
总结
原生插件开发是 React Native 进阶必备技能,通过它可以:
- 实现高性能的原生功能(如摄像头、蓝牙)。
- 复用已有原生代码库。
- 优化关键性能瓶颈。