版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wj610671226/article/details/87473524
重拾React Native笔记之–原生模块的编写
iOS原生模块
- 原生模块
原生模块创建方式及内容包括:
1、创建一个原生模块遵守RCTBridgeModule协议
2、利用RCT_EXPORT_MODULE()宏导出到JS端调用的方法
3、需要导出的常量、枚举等
4、向JavaScript端发送事件等(继承RCTEventEmitter类)
5、多线程的控制
Demo:
NativeModuleDemo.h
@interface NativeModuleDemo : NSObject<RCTBridgeModule>
@end
导出JavaScript需要调用的方法
1、导出不带回调的方法
2、导出带回调的方法(包括Promises方式)
// 1、不带回调的方法
RCT_EXPORT_METHOD(callNativeMethod:(NSDictionary *)param) {
NSLog(@"callNativeMethod js param = %@", param);
NSLog(@"thread = %@", [NSThread currentThread]);
}
JavaScript端调用方式:
import { NativeModules } from 'react-native';
const myNativeModule = NativeModules.NativeModuleDemo;
myNativeModule.callNativeMethod({"name": 'zhangdan'});
// 2、带回调的方法 RCTResponseSenderBlock只接受一个参数是数组
RCT_EXPORT_METHOD(callNativeMethod:(NSDictionary *)param callback:(RCTResponseSenderBlock)callback) {
NSLog(@"js param = %@", param);
callback(@[@"原生回传的参数"]);
}
JavaScript端调用方式:
myNativeModule.callNativeMethod({"name": 'zhangdan'}, (callback) => {
console.log(callback);
});
// 3、采用 Promises 搭配 async/await 方式调用的原生方法
RCT_EXPORT_METHOD(callNativeMethod:(NSDictionary *)param resolve:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSLog(@"Promises 原生方法 param = %@", param);
NSError * error = [NSError errorWithDomain:@"构建错误" code:1000 userInfo:nil];
if (!error) {
resolve(@"成功的回调");
return;
}
reject(@"errorCode", @"errorMesage", error);
}
JavaScript端调用:
try {
let param = await myNativeModule.callNativeMethod({"name" : "zhangsan"});
console.log('param = ' + param);
} catch (error) {
console.log(error);
}
常量的导出:
- (NSDictionary *)constantsToExport
{
return @{ @"ConstKey": @"ConstValue" };
}
向JavaScript端发送事件:
1、原生模块继承自RCTEventEmitter类
2、重写supportedEvents方法提供发送的事件
NativeModuleDemo.h
@interface NativeModuleDemo : RCTEventEmitter<RCTBridgeModule>
@end
NativeModuleDemo.m
// 提供事件name
- (NSArray<NSString *> *)supportedEvents
{
return @[@"EventReminderDemo"];
}
// 发送事件
[self sendEventWithName:@"EventReminder" body:@"参数"];
JavaScript端监听处理
import { NativeEventEmitter, NativeModules } from 'react-native';
const MyNativeModule = NativeModules.NativeModuleDemo;
const nativeEmitter = new NativeEventEmitter(MyNativeModule);
// 添加监听
const subscription = nativeEmitter.addListener(
'EventReminderDemo',
(param) => console.log(param)
);
- 原生视图
原生视图的构建主要有一下几点步骤:
1、创建一个继承RCTViewManager的视图管理类(如:NativeViewManager,不带Manager后缀也可以)
2、添加宏RCT_EXPORT_MODULE()
3、实现view方法,提供原生视图
4、根据需要导出RN端需要访问的属性和方法(提供的属性,视图中一定要存在,并且有set方法)
Demo:
// NativeViewManager.h
#import <React/RCTViewManager.h>
@interface NativeViewManager : RCTViewManager
@end
// NativeViewManager.m
@implementation NativeViewManager
RCT_EXPORT_MODULE()
// 导出属性
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
// 自定义属性
//RCT_CUSTOM_VIEW_PROPERTY(<#name#>, <#type#>, <#viewClass#>)
RCT_EXPORT_VIEW_PROPERTY(onNativeEvent, RCTBubblingEventBlock)
- (UIView *)view
{
// 创建原生视图
NativeView * nativeView = [NativeView loadWithXib];
return nativeView;
}
// 在JavaScript端使用该原生视图
1、创建NativeView.js
import { requireNativeComponent } from 'react-native';
import React from 'react';
import PropTypes from 'prop-types';
class NativeView extends React.Component {
render() {
return <MyNativeView />;
}
}
// 命令行安装 npm install prop-types --save
// 原生端提供的属性文档
NativeView.propTypes = {
title: PropTypes.string, // 原生端必须提供相应属性的set方法
customNativeEvent: PropTypes.func
};
// requireNativeComponent 自动把'NativeView'解析为'NativeViewManager'
var MyNativeView = requireNativeComponent('NativeView', null);;
export default MyNativeView;
// 使用
<NativeView title="测试" style={{width: 200, height: 80, backgroundColor: 'red'}}></NativeView>
Android中原生模块
- 原生模块
Android中原生模块的创建包括以下步骤:
1、创建一个Java类继承ReactContextBaseJavaModule类
2、重写getName方法,返回提供给JavaScript端调用的原生模块名称
3、重写getConstants方法,提供JavaScript端访问的常量
4、利用注解@ReactMethod提供JavaScript端调用的方法
5、创建个Java类实现ReactPackage接口,添加自定义的模块
6、在MainApplication.java中的getPackages()方法中创建这个模块
Demo:
// 创建自己的模块
// 原生模块继承 ReactContextBaseJavaModule 类
public class ToastModule extends ReactContextBaseJavaModule {
private static final String DURATION_SHORT_KEY = "SHORT";
private static final String DURATION_LONG_KEY = "LONG";
private ReactContext mReactContext;
public ToastModule(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
}
@Override
public String getName() { // 返回JavaScript端的模块名称
return "ToastDemoModule";
}
@Nullable
@Override
public Map<String, Object> getConstants() { // 提供给JavaScript端访问的常量
final Map<String, Object> constants = new HashMap<>();
constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
return constants;
}
// 定义提供给javaScript访问的方法, 返回值必须是void
@ReactMethod
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
// 提供给js端调用的方法
@ReactMethod
public void callAndroidMethod(String param, Callback errorCallback, Callback successCallback) {
Log.i("callAndroidMethod", param.toString());
try {
Thread.sleep(1000);
// 成功回调
successCallback.invoke("回调成功");
} catch (InterruptedException e) {
e.printStackTrace();
// 失败的回调
errorCallback.invoke("失败");
}
}
// 采用Promiss方式
@ReactMethod
public void callAndroidMethodPromises(String param, Promise promise) {
Log.i("callAndroidMethod", param.toString());
try {
Thread.sleep(1000);
int result = 5 / 0;
// 成功回调
promise.resolve("回调成功" + result);
} catch (Exception e) {
e.printStackTrace();
// 失败的回调
promise.reject("0001", "错误信息 = " + e.getMessage());
}
}
// 发送事件到js端
@ReactMethod
public void sendEventTest() {
// 构建发送的参数
WritableMap writableMap = Arguments.createMap();
writableMap.putString("name", "zhansan");
sendEvent(mReactContext, "androidEmitter",writableMap);
}
private void sendEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
// 注册模块
public class CustomToastPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ToastModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
// 在MainApplication.java中注册自己的模块
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CustomToastPackage() // 注册自己实现的package模块
);
}
// JavaScript中使用自己创建的原生模块
import { NativeModules } from 'react-native';
const androidToast = NativeModules.ToastDemoModule;
// 简单使用
androidToast.show("toast", androidToast.LONG);
// 调用原生提供的方法,并传递参数
androidToast.callAndroidMethod("js 传递给原生端的 参数", (error) => {
androidToast.show(error, androidToast.LONG);
},(success) => {
androidToast.show(success, androidToast.LONG)
});
// 原生采用Promiss方法提供的方式,js端调用
try {
const result = await androidToast.callAndroidMethodPromises("js 传递给原生端的 参数");
androidToast.show(result, androidToast.LONG);
} catch (error) {
alert(error);
}
// JavaScript端监听原生发送的事件
DeviceEventEmitter.addListener('androidEmitter', (e: Event) => {
alert("androidEmitter");
});