美文网首页Android开发Android知识
2017-3-28(React-Native与Android原生

2017-3-28(React-Native与Android原生

作者: 721d739b6619 | 来源:发表于2017-03-31 20:59 被阅读3256次

    本文参考的文章链接如下:
    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<String, Object> getConstants() {
            //让js那边能够使用这些常量
            Map<String,Object> 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;
        }
    }
    
    

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

    Paste_Image.png

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

    Paste_Image.png

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

    Paste_Image.png

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

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

    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<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();
    
            modules.add(new ToastExample(reactContext));
            return modules;
        }
    
        @Override
        public List<Class<? extends JavaScriptModule>> createJSModules() {
            return Collections.emptyList();
        }
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    }
    
    

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

    Paste_Image.png

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

    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<ReactPackage> getPackages() {
                return Arrays.<ReactPackage>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方法

    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';
    
    Paste_Image.png
    loginInOnPress (){
            // ToastForAndroid.show(ToastForAndroid.LONG);
            ToastForAndroid.testAndroidCallbackMethod("hello",(obj)=>{
                console.log(obj);
            });
        }
    

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

    Paste_Image.png

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

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

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

    相关文章

      网友评论

        本文标题:2017-3-28(React-Native与Android原生

        本文链接:https://www.haomeiwen.com/subject/vefjottx.html