(八)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>

相关文章

导入moment 使用方式 年月日,时分秒 星期几 相对时间 7天后 2小时后 明天 将毫秒转换成年月日
@ 一、前言 为什么介绍redux-actions呢? 第一次见到主要是接手公司原有的项目,发现有之前的大佬在处理...
十大React Hook库 原文地址:https://dev.to/bornfightcompany/top-10-react-hook-libraries-4065 原文...
React生命周期 React的生命周期从广义上分为挂载、渲染、卸载三个阶段,在React的整个生命周期中提供很...
React虚拟DOM的理解 Virtual DOM是一棵以JavaScript对象作为基础的树,每一个节点可以将其称为VNode,用...
React中JSX的理解 JSX是快速生成react元素的一种语法,实际是React.createElement(component, props, ....