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