1. 程式人生 > >(八)React Native實現呼叫android原生java方法並實現廣播的傳送和接受

(八)React Native實現呼叫android原生java方法並實現廣播的傳送和接受

接觸到混合應用開發提議後,首先想到了之前學的ionic,其次便是這兩年火遍全球的RN,由於ionic框架用的angular.js,而且angular1和angular2寫法區別很大,angular2對於初學者還是比較好接受的,但是angular1寫的很亂,程式碼很難維護,便放棄了。決定用RN後覺得還是蠻順手的,跟angular2很相似,又是ES6,很快便能入手,框架的選擇還需要考慮的是外掛的支援,尤其是:推送,廣播,二維碼掃描,服務,本地資料儲存這些功能能否實現,由於要與硬體廠商對接,用到廣播,就研究了一下如何用RN實現廣播。

百度了所有的資料就是找不到如何RN實現原生廣播,沒有一篇類似的,於是檢視一下RN專案結構,看了安卓後決定用AS載入一下看看能不能在裡邊編輯一下,發現MainApplication能夠在應用啟動時執行onCreate方法,那麼我就一定能在onCreate時Toast一段話或傳送一個廣播的動作,那麼接受傳送廣播基本實現了,果不其然廣播真的接受到了。那麼下面我要解決的問題便是RN事件如何觸發android原生java程式碼中的方法,如果這個問題解決了,我就能通過點選事件傳送一個廣播。

一、RN專案新增廣播,跟原生新增廣播一樣,兩種方法,我們採用其中一種常駐廣播:

<receiver android:name=".MyBroadcastReceiver">
            <intent-filter>
                <action android:name="com.example.broadcastreceiverdemo.BROADCAST"></action>
            </intent-filter>
        </receiver>

廣播要處理的就是toast一段話:

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context arg0, Intent arg1) {
        // TODO Auto-generated method stub
        String string=arg1.getStringExtra("data");
        Toast.makeText(arg0, "received:"+string, Toast.LENGTH_SHORT).show();

    }

}

二、React Native 呼叫原生Android模組
該方法參考:http://www.cnblogs.com/lgp142332/p/6024280.html
我們首先來建立一個原生模組。一個原生模組是一個繼承了ReactContextBaseJavaModule的Java類,它可以實現一些JavaScript所需的功能。我們這裡的目標是可以在JavaScript裡寫ToastAndroid.show(‘Awesome’, ToastAndroid.SHORT);,來調起一個Toast通知。

package com.testproject.module;

import android.content.Intent;
import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

/**
 * Created by Administrator on 2017/4/15.
 */

public class SendBroadcastModule extends ReactContextBaseJavaModule {

    public SendBroadcastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "SendBroadcast";
    }

    @ReactMethod
    public void sendBroadcast(){
        //傳送廣播
        Toast.makeText(getReactApplicationContext(),"開始傳送...", Toast.LENGTH_SHORT).show();
        Intent intent=new Intent("com.example.broadcastreceiverdemo.BROADCAST");
        intent.putExtra("data", "hello");
        getReactApplicationContext().sendBroadcast(intent);
    }

    @Override
    public boolean canOverrideExistingModule() {
        return true;
    }
}

ReactContextBaseJavaModule要求派生類實現getName方法。這個函式用於返回一個字串名字,這個名字在JavaScript端標記這個模組。這裡我們把這個模組叫做SendBroadcast,這樣就可以在JavaScript中通過React.NativeModules.SendBroadcast訪問到這個模組。

注意:模組名前的RCT字首會被自動移除。所以如果返回的字串為”RCTSendBroadcast”,在JavaScript端依然通過React.NativeModules.SendBroadcast訪問到這個模組。

要匯出一個方法給JavaScript使用,Java方法需要使用註解@ReactMethod。方法的返回型別必須為void。React Native的跨語言訪問是非同步進行的,所以想要給JavaScript返回一個值的唯一辦法是使用回撥函式或者傳送事件。

註冊模組

在Java這邊要做的最後一件事就是註冊這個模組。我們需要在應用的Package類的createNativeModules方法中新增這個模組。如果模組沒有被註冊,它也無法在JavaScript中被訪問到。

package com.testproject.module;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.testproject.module.SendBroadcastModule;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by Administrator on 2017/4/15.
 */

public class SendBroadcastPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules=new ArrayList<>();
        modules.add(new SendBroadcastModule(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

注意:重寫的兩個方法createJSModules和createViewManagers不能return null,否則執行會報紅屏AddAll的錯誤,一定要return Collections.emptyList();

接著我們需要在MainApplication中的getPackages方法中註冊:

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
              new BarcodeScannerPackage(),
              new RealmReactPackage(),
              new SendBroadcastPackage()//註冊廣播模組
      );
    }

接下來便是RN的js程式碼了:

為了讓你的功能從JavaScript端訪問起來更為方便,通常我們都會把原生模組封裝成一個JavaScript模組。這不是必須的,但省下了每次都從NativeModules中獲取對應模組的步驟。這個JS檔案也可以用於新增一些其他JavaScript端實現的功能。

var { NativeModules } = require('react-native');

export { NativeModules as default } 

然後在你需要呼叫的componet中引入NativeModules並呼叫傳送廣播的方法:

<Text onPress={ () => {
              ToastAndroid.show("。。。",ToastAndroid.SHORT);
              NativeModules.SendBroadcast.sendBroadcast();
            }}>傳送廣播</Text>