2017-3-28(React-Native与Android原生代码交互)

本文参考的文章链接如下:
React-Native 与原生的3种交互通信(Android)
React Native 调用原生Android模块

原生与React-NativeJSX交互的涉及到的java类:

  • ReactContextBaseJavaModule : 用于自定义实现原生代码调用
  • ReactPackage :用于注册java代码在JSX代码使用
  • ReactApplication : 实现ReactNativeHost单例方式存储继承ReactPackage

继承ReactContextBaseJavaModule

package com.reactnativeproject;

import android.widget.Toast;

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

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

/**
 * Created by Gww on 2017/3/27.
 * 原生的代码,之后与JS交互
 */
public class ToastExample extends ReactContextBaseJavaModule{

    private static final String LONG_TIME = "LONG";
    private static final String SHORT_TIME = "SHORT";


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

    /**
     * return string 这个名字在JavaScript端标记这个模块
     * 这样就可以在JavaScript中通过React.NativeModules.ToastForAndroid访问到这个模块
     * */
    @Override
    public String getName() {
        return "ToastForAndroid";
    }

    /**
     * return 需要导出给JavaScript使用的常量。它并不一定需要实现,但在定义一些可以被JavaScript同步访问到的预定义的值时非常有用。
     * */
    @Override
    public Map getConstants() {
        //让js那边能够使用这些常量
        Map constants = new HashMap<>();
        constants.put(LONG_TIME,Toast.LENGTH_LONG);
        constants.put(SHORT_TIME,Toast.LENGTH_SHORT);
        return constants;
//        return super.getConstants();
    }

    /**
     * 该方法就是给js使用
     * Java方法需要使用注解@ReactMethod。
     * 方法的返回类型必须为void。
     * React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件
     * */
    @ReactMethod
    public void show(int duration){
        Toast.makeText(getReactApplicationContext(),"message",duration).show();
    }

    /**
     * 测试安卓的回调方法
     * */
    @ReactMethod
    public void testAndroidCallbackMethod(String msg, Callback callback){
        Toast.makeText(getReactApplicationContext(),msg,Toast.LENGTH_LONG).show();
        callback.invoke("abc");
    }

    @Override
    public boolean canOverrideExistingModule() {
        //这里需要返回true
        return true;
    }
}

讲解一下部分核心代码:
这个类其实就是实现原生代码的调用。

2017-3-28(React-Native与Android原生代码交互)_第1张图片
Paste_Image.png

"ToastForAndroid"就是JS调用的那个对象变量。

2017-3-28(React-Native与Android原生代码交互)_第2张图片
Paste_Image.png

这里也定义了两个常量,放在这个集合中可以供JS调用。

2017-3-28(React-Native与Android原生代码交互)_第3张图片
Paste_Image.png

该就是供JS调用的方法,这里在java代码需要加注解@ReactMethod
不然在JS那边会调用不了。

最后一个其实也是给JS调用的方法,不过这个方法提供了回调,即

2017-3-28(React-Native与Android原生代码交互)_第4张图片
Paste_Image.png

callback.invoke('abc');这里可以把信息回调给JS那边。

ReactPackage

现在说另一个类ReactPackage,其实该类的基本作用就是把继承ReactContextBaseJavaModule类的方法注册到JS里。上代码吧:

package com.reactnativeproject;

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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Created by Gww on 2017/3/27.
 * 在reactnative注册用于js调用
 */
public class ExampleReactNativePackage implements ReactPackage{
    @Override
    public List createNativeModules(ReactApplicationContext reactContext) {
        List modules = new ArrayList<>();

        modules.add(new ToastExample(reactContext));
        return modules;
    }

    @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

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

其中就把ToastExample对象添加到modules这个list上。
还有两个方法返回Collections.emptyList();

2017-3-28(React-Native与Android原生代码交互)_第5张图片
Paste_Image.png

最后一个java类Application,这个写过Android的应该对这个类并不陌生,其实就是这个Application的生命周期贯穿整个app程序。程序初始化会调用该类的onCreate方法。

2017-3-28(React-Native与Android原生代码交互)_第6张图片
Paste_Image.png

在ReactNative中,我们需要Application这个类实现ReactApplication这个接口,其实我们初始化一个ReactNative项目的java代码已经有这个Application类也已经实现了该接口。在这里其实我们只需要在Application这个对象构建时new一个ReactnativeHost对象,在getPackages方法重写一下,返回一个数组,该数组新增一个之前用于注册java方法的ExampleReactNativePackage对象。

这里说一下如果是原生跟ReactNative混搭的话,自己项目拥有一个Application类的话其实就按照接口的操作即可。上代码吧:

package com.reactnativeproject;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;//这是true,返回false是会报错找不到AppRegistry
        }

        @Override
        protected List getPackages() {
            return Arrays.asList(
                    new MainReactPackage(),
                    new ExampleReactNativePackage()/*自定义的一个package*/
            );
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ false);
    }
}

基本上java这边就这么多东西了。

然后看看js那边怎么调用和导出一个对象:

JS导出
import {NativeModules} from 'react-native';

export default NativeModules.ToastForAndroid;

其中ToastForAndroid就是对应java那边所说的getName方法

2017-3-28(React-Native与Android原生代码交互)_第7张图片
Paste_Image.png

这个java和js一一对应的,不然JS会找不到此对象。

JS调用

调用前需要导入刚才的ToastForAndroid对象供这边的JS使用:

import React,{Component} from 'react';
import {
    StyleSheet,Text,Image,View, TextInput, TouchableHighlight, Navigator, BackAndroid,Platform
} from 'react-native';
import ToastUtil from '../utils/ToastUtil';//export default的class就可以不用{}括组件,直接用ToastUtil
import HelloWorld from '../00_helloworld_demo/HelloWorld';
import ToastForAndroid from '../utils/ToastForAndroid';
2017-3-28(React-Native与Android原生代码交互)_第8张图片
Paste_Image.png
loginInOnPress (){
        // ToastForAndroid.show(ToastForAndroid.LONG);
        ToastForAndroid.testAndroidCallbackMethod("hello",(obj)=>{
            console.log(obj);
        });
    }

上面是js代码,一个是没有回调的Toast方法,另外一个是有回调的Toast方法。
"hello"是传参给java那边,箭头函数:(obj)=>{console.log(obj)};是回调方法,即刚刚

2017-3-28(React-Native与Android原生代码交互)_第9张图片
Paste_Image.png

java那边的‘abc’其实就是js这边的obj对象

基本上ReactNative的JS与Android的原生就这样交互的。其实上边一篇文章中是有三种交互方式的,我这里只说了一种,当时我自己也试了另外的一种,剩下最后一种没有尝试,有空的童鞋可以试试。

最后由于本人第一次写分享文章有什么遗漏或不好望见谅,日后会把demo的源码上传的github上供各位分享。

你可能感兴趣的:(2017-3-28(React-Native与Android原生代码交互))