React Native與Android通訊互動

黑馬大前端發表於2018-06-25

  安卓系統為我們提供了webview來載入網頁,為了讓webview載入的網頁可以與App互動,系統提供了一套機制幫助我們更方便的實現通訊。同樣為了實現React Native與原生App之間的通訊,Facebook也實現了自己的一套互動機制.

通過平時與IOS和安卓的同學同事除錯,大致歸納了有以下四種:


  1. RCTDeviceEventEmitter 事件方式

  2. Callback 回撥方式

  3. Promise 信任方式

  4. 直傳常量資料




先比較下優缺點:eventMitter的形式可任意時刻傳遞,由Native主導控制,callback形式由JS呼叫Native返回,但是是非同步的時機不確定,所以有Promise形式,但是要不斷的JS呼叫如輪詢。直傳常量跨域傳值,只能從原生端向RN端傳遞。RN端可通過 NativeModules.[module名].[引數名] 的方式獲取



瞭解了三者的通訊方式,怎麼能少了程式碼的描述!我們來看看程式碼如何實現。大致的實現步驟如下:


以下是安卓程式碼的編寫 eventMitter


1. 定義Module類,繼承ReactContextBaseJavaModule, 在Module類中,我們定義互動的方法,例如RN呼叫Native的方法,Native呼叫RN的方法等。

    @Override

    public String getName() {

    return MODULE_NAME;

    }

/**

* RN呼叫Native的方法在module中定義一個方法,並用@ReactMethod 註解標註:表明該方法會被RN呼叫。即被RN呼叫的原生方法必須使用@ReactMethod註解標註。

*/

@ReactMethod

public void rnCallNative(String a) {

// XXX.

    mContext.startActivity(XX);

}


/**

* Native呼叫RN 上面程式碼定義了原生方法,通過在Android層呼叫RN層。使用ReactContext的getJSModule方法,emit來傳送訊息。同樣,emit的第一個引數要與RN層中addListener方法的第一個引數相同。

* @param msg

*/

public void nativeCallRn(String msg) {         mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(  EVENT_NAME,msg);

}


2. 定義Package類,繼承ReactPackage實現Package的createNativeModules方法,將Module例項新增到集合。

/** 通訊Package類 */

public class CommPackage implements ReactPackage {

    public CommModule mModule;

/**

* 建立Native Module 在createNativeModules方法中,初始化集合,並將module例項新增進集合,返回集合例項。

* @param reactContext

*/

@Override

public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

    List<NativeModule> modules = new ArrayList<>();

    mModule = new CommModule(reactContext);

    modules.add(mModule);

    return modules;

}

@Override

public List<Class<? extends JavaScriptModule>> createJSModules() {

    return Collections.emptyList();

}

@Override

public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {

    return Collections.emptyList();

  }

}


3. 定義Application,繼承ReactApplication實現getPackages方法,將Package例項新增到getPackages下的集合。

private static final CommPackage mCommPackage = new CommPackage();

**

* 獲取 reactPackage getPackages方法中,將Package例項新增到Arrays中即可完成註冊

*/

public static CommPackage getReactPackage() {

    return mCommPackage;

}


以下是RN程式碼的編寫,通過 RCTDeviceEventEmitter 模式進行通訊互動。互動都是以主動方式為主


1. 呼叫原生程式碼

/**

* 呼叫原生程式碼 在React Native層,通過NativeModules呼叫commModule

*/

nativeCall() {

    NativeModules.commModule.rnCallNative(xxx);

}

2. 接收原生呼叫


/**

* 接收原生呼叫通過DeviceEventEmitter註冊監聽,類似於Android中的監聽事件。第一個引數標識名稱,要與Module中emit的Event Name相同。第二個引數即為處理回掉IOS應該為NativeEventEmitter

*/

componentDidMount() {

    DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{ });

}




Callback形式 RN層呼叫Native層,Native層處理完成後,回撥RN層

**

* Callback 方式

* rn呼叫Native,並獲取返回值

*/

@ReactMethod

public void rnCallNativeCb(String msg, Callback callback) {

callback.invoke(xxx); // 2.回撥RN,即將處理結果返回給RN

}

// RN

callbackComm(msg) {

    NativeModules.commModule.rnCallNativeCb(msg,(result) => {})

}



Promise形式 同樣是RN層呼叫Native層,Native層處理完成後,回撥RN層

@ReactMethod

public void rnCallNativePromise(String msg, Promise promise) {

    promise.resolve(xxx);

}

// RN

promiseComm(msg) {

NativeModules.commModule.rnCallNativePromise(msg).then((result) =>{}).catch((error)           =>  {console.log(error)});

}


直傳常量資料(原生向RN)

@Nullable

@Override

@return a map of constants this module exports to JS. Supports JSON types.

從原始碼註釋中可以看出,該方法是返回一個Map型別的常量,匯出到JS端(即RN)。支援JSON 型別。所以,我們只需要重寫方法,宣告Map集合,向其中新增常量後,返回即可


public Map<String, Object> getConstants() {

    return super.getConstants();

}

// Ours Android

@Nullable

@Override

public Map<String, Object> getConstants() {

    Map<String,Object> params = new HashMap<>();

    params.put("Constantxx","xxx");

    return params;

}

// Ours RN

componentWillMount() {

    let result = NativeModules.MyModule.Constantxx

}  


相關文章