React Native 原生模块封装:支付宝示例

2,676 阅读3分钟

React Native本身已经提供很多可用的模块和组件,有一部分我们需要的模块和组件仍然无法直接提供,需要借助原生的代码来提供。封装原生模块和视图导出使用,也可以让React Native拥有android和ios平台的强大生态链和使用众多第三方类库。

原生模块

以下以支付宝支付模块为实例

android支付宝

模块实现

AlipayModule.java

// 模块继承自ReactContextBaseJavaModule
public class AlipayModule extends ReactContextBaseJavaModule {

  // 默认构造方法
  public AlipayModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  // 模块名
  @Override
  public String getName() {
    return "AlipayModule";
  }

  // 添加@ReactMethod注解导出方法
  // promise需放在最后
  @ReactMethod
  public void pay(final String orderInfo, final Promise promise) {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        PayTask alipay = new PayTask(getCurrentActivity());
        Map<String, String> result = alipay.payV2(orderInfo,true);
        Log.i("AlipayModule", "resultStatus: " + result.get("resultStatus"));
        if ("9000".equals(result.get("resultStatus"))) {
          promise.resolve(true);
        } else {
          promise.resolve(false);
        }
      }
    };
    Thread thread = new Thread(runnable);
    thread.start();
  }

}

模块注册

MyReactPackage.java

// 实现ReactPackage接口
// 用于注册导出的模块和视图
public class MyReactPackage implements ReactPackage {

  // 原生模块注册
  @Override
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    return Arrays.<NativeModule>asList(
        new AlipayModule(reactContext)
    );
  }

  // 原生视图注册
  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList();
  }
}

包注册

在MainApplication getPackages方法中添加new MyReactPackage()

ios支付宝

模块实现

AlipayModule.h

#import <React/RCTBridgeModule.h>

@interface AlipayModule : NSObject<RCTBridgeModule>

@end

AlipayModule.m

#import "AlipayModule.h"
#import <AlipaySDK/AlipaySDK.h>

@interface AlipayModule()

@end

@implementation AlipayModule

// 添加宏,导出模块
RCT_EXPORT_MODULE();
  
// 使用宏,导出方法,resolve和reject为promise方法
RCT_EXPORT_METHOD(pay: (NSString *) orderInfo resolver: (RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject)
{
  [[AlipaySDK defaultService] payOrder:orderInfo fromScheme:@"本app的schema" callback:^(NSDictionary *resultDic)
  {
    if ([@"9000" isEqualToString: [resultDic valueForKey:@"resultStatus"]]) {
      resolve(@(YES));
    } else {
      resolve(@(NO));
    }
  }];
}

@end

js层

方法导出

Alipay.ts

import {NativeModules} from 'react-native';

export interface Alipay {
  pay(orderInfo: string): Promise<boolean>;
}

export const Alipay = NativeModules.AlipayModule as Alipay;

js层使用

import Alipay from './Alipay';

try {
    const result = await Alipay.pay(orderInfo);
    if (result) console.log('支付成功');
} catch(e) {
    console.error(e);
}

原生模块导出相对而言还是非常简单的,在上面支付宝支付的实例中演示了导出一个简单的模块和promise在原生代码中的注入和在js层的使用。

原生js交互

原生调用js

js中调用模块代码,模块中直接导出即可,有时候我们也会需要在原生代码中去调用js的代码,例如做事件通知等。

android调用js

事件名为js层监听的名字,值可以为int、float等,与原生方法一直

reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit("事件名", 值);

js监听android调用

const listener = DeviceEventEmitter.addListener('事件名',
        data => console.log('android调用', data));
// 调用完成移除监听        
listener.remove();

ios调用js

模块.h文件

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

// 修改.h中NSObject为RCTEventEmitter
@interface XXXModule : RCTEventEmitter<RCTBridgeModule>

@end

模块.m文件

// 添加支持事件名
- (NSArray<NSString *> *)supportedEvents
{
  return @[@"event1", @"event2"];
}

// 事件发送
// float body [NSNumber numberWithFloat:num]
[self sendEventWithName:@"event1" body:body];

js监听ios调用

// 获取模块监听者
// XXXModule为模块名称,与导出的名字一致
const eventEmitter = new NativeEventEmitter(NativeModules.XXXModule);

const listener = eventEmitter.addListener('事件名',
          data => console.log('ios调用', data));
// 监听完成后移除          
listener.remove();

ios和android发送事件封装方法不一样,在js层监听方法也不一样,所以需要注意平台,一般事件是在耗时操作过程中监听,在开始时候开始监听,在结束后应马上移除监听。