重拾React Native笔记之--原生模块的编写

版权声明:本文为博主原创文章,未经博主允许不得转载。 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");
});

猜你喜欢

转载自blog.csdn.net/wj610671226/article/details/87473524