React Native 原生模組封裝:支付寶示例

qiushijie發表於2019-04-02

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層監聽方法也不一樣,所以需要注意平臺,一般事件是在耗時操作過程中監聽,在開始時候開始監聽,在結束後應馬上移除監聽。

相關文章