react-native:调用Native方法(Android)

有的时候我们使用React Native无法满足一些使用特定场景,这个时候就需要使用原生的Android方法,比如一些耗时的写操作,操作数据库或者多线程操作等。
React Native可以直接调用系统的API(java方法),实现JavaScript与java语言的通讯,如果React Native中没有满足我们需求的Api,可以封装原生的方法提供JavaScript调用。
JavaScript和java通信是通过bridge实现的,在java层和JavaScript层的bridge分别存有相同的一份模块配置表。Java与JavaScript相互通信时,通过bridge里的配置表将所调用模块方式转为{moduleID,methodID,args}的形式传递给处理层,处理层通过bridge里的配置表找到对应的方法执行,如果有callback,则回传给调用层,如果没有执行就结束。

我们通过JavaScript调用Toast的例子来看下,JavaScript如何调用Java代码的。

新建一个项目:

react-native init RNAndroid

在android的项目目录下面新建一个类RNToastModule,此类需要继承ReactContextBaseJavaModule

ReactContextBaseJavaModule

ReactContextBaseJavaModule是一个抽象类,是用来被JavaScript调用对象的父类,我们需要Override一些ReactContextBaseJavaModule的方法。

首先要Override getName()方法:

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

这个方法的返回值就是JavaScript中调用的名称,比如我们命名为RNToastAndroid,在JavaScript中可以这样调用:

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

然后我们可以选择性的覆盖getConstants()方法:
这个方法的用在JavaScript和Java直接定义公用常量的,它使用key-value的方式保存。
在Java中定义两个变量:

   private static final String DURAION_SHORT_KEY = "SHORT";
   private static final String DURAION_LONG_KEY = "LONG";

getConstants()中给两个字符串赋值:

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURAION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURAION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
    }

我们把Toast的两个常量放在了 constants中。
在JavaScript可以这样调用:

rnToastAndroid.show('Hello Toast of native', rnToastAndroid.SHORT);

最后我们定义一个React调用的方法:

    @ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();

    }

这个使用了annotation定义的方式必须加上@ReactMethod
这里的参数只能React Navive定义的参数。

ReactMethod的对应参数

@ReactMethod中传的参数必须是JavaScript和Java对应的。

Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array

注册ReactPackage

新建一个RNJavaReactPackage类,继承ReactPackage。

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new RNToastModule(reactContext));
        return modules;
    }

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

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return new ArrayList<>();
    }

RNJavaReactPackage创建了一个NativeModule的List。把RNToastModule的实例都添加进去提供给JavaScript层调用。

添加ReactPackage

android/app/src/main/java/com/your-app-name/中有个MainActivity.java其中的getPackages()方法用来返回用来的ReactPackage包,添加定义好的RNJavaReactPackage的实例
以上内容已经在0.31.0中更新。
新版本使用ReactNativeHost替换ReactInstanceManager,ReactNativeHost是设置Android相关配置的类。
需要在Application中实例化。
首先实现新建一个ReactNativeHost的实例并添加RNJavaReactPackage的实例:

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 
   @Override   
   protected boolean getUseDeveloperSupport() {   
       return BuildConfig.DEBUG;   
   } 
   @Override   
   protected List<ReactPackage> getPackages() { 
         return Arrays.<ReactPackage>asList(
                new MainReactPackage(),         
               new RNJavaReactPackage()       
         ); 
     }
};

实现ReactApplication:

public class MainApplication extends Application implements ReactApplication {    
    @Override    
    public ReactNativeHost getReactNativeHost() {      
        return mReactNativeHost;   
   }
}

JavaScript中调用

在JavaScript显示Toast:

'use strict';

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

rnToastAndroid.show('Hello Toast of native', rnToastAndroid.SHORT);

这样就完成了从JavaScript中直接调用了Java中定义的方法。

代码地址:https://github.com/jjz/react-...


姜家志
尽力了!才有资格说运气不好。

尽力了!才有资格说运气不好。

2.3k 声望
148 粉丝
0 条评论
推荐阅读
gitlab-runner升级到最新版本
出现这个问题的原因是因为gitlab-runner的版本过低,当前gitlab-runner最新版本为:12.7.1解决办法:升级gitlab-runner为最新版本,先升级包:

姜家志阅读 5k

安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城31阅读 7.1k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco19阅读 2k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.6k评论 3

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 19.8k评论 9

尽力了!才有资格说运气不好。

2.3k 声望
148 粉丝
宣传栏