本文参考的文章链接如下:
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;
}
}
讲解一下部分核心代码:
这个类其实就是实现原生代码的调用。
"ToastForAndroid"就是JS调用的那个对象变量。
这里也定义了两个常量,放在这个集合中可以供JS调用。
该就是供JS调用的方法,这里在java代码需要加注解@ReactMethod
不然在JS那边会调用不了。
最后一个其实也是给JS调用的方法,不过这个方法提供了回调,即
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();
最后一个java类Application,这个写过Android的应该对这个类并不陌生,其实就是这个Application的生命周期贯穿整个app程序。程序初始化会调用该类的onCreate方法。
在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方法
这个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';
loginInOnPress (){
// ToastForAndroid.show(ToastForAndroid.LONG);
ToastForAndroid.testAndroidCallbackMethod("hello",(obj)=>{
console.log(obj);
});
}
上面是js代码,一个是没有回调的Toast方法,另外一个是有回调的Toast方法。
"hello"是传参给java那边,箭头函数:(obj)=>{console.log(obj)};是回调方法,即刚刚
java那边的‘abc’其实就是js这边的obj对象
基本上ReactNative的JS与Android的原生就这样交互的。其实上边一篇文章中是有三种交互方式的,我这里只说了一种,当时我自己也试了另外的一种,剩下最后一种没有尝试,有空的童鞋可以试试。
最后由于本人第一次写分享文章有什么遗漏或不好望见谅,日后会把demo的源码上传的github上供各位分享。