旧机宝开发笔记之:RN应用和Native应用之间的通信(入门)

前言

RN主要用于编写UI,原生API的调用、网络通信等等复杂的逻辑则大多是通过原生代码去实现的。那么RN和原生代码是怎么交互的呢?
官网在此
以下以安卓平台原生为例,我们按照官网的教程来实现这样一个交互demo,借此来了解互相调用的用法。不过我们的起点是一个刚刚创建的RN应用(通过

npx react-native init

来创建的),可能有些操作已经存在,不过这些步骤不会因此而被忽略。

思路

开始之前先来理清楚一下思路。
首先是RN调用原生接口:

  1. 第一步,很显然的我们要在android里实现一个方法,实现具体的逻辑供RN调用。
  2. 第二步,我们需要通过RN框架把这个方法“传递”给RN应用。
  3. 第三步,RN应用调用“传递”过来的方法,实现RN对原生的调用。

而原生对RN的调用则刚好相反。
那开始试试吧。

定义原生方法

假设我们要通过原生逻辑来显示一个Toast(这种方式逻辑简单、表现明显),我们先定义一个ToastUtil类,并且为其增加一个显示Toast的方法show()。

public class ToastUtil {
    public void show(Context context,String message){
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
}

将原生方法通过RN框架“传给”RN应用

现在需要把我们的工具类交给RN并由其传递给RN应用了。分析官方示例,将工具类交给RN的路径抽离如下图所示:
在这里插入图片描述

  1. RN框架提供了一个ReactApplication接口,正如它名字想表达的一样,这是一个要由android的Application实现的接口。
public interface ReactApplication {

  /** Get the default {@link ReactNativeHost} for this app. */
  ReactNativeHost getReactNativeHost();
}

其中要求实现方法getReactNativeHost。对于已经接入RN的android示例代码来说,这些操作是现成的。

public class MainApplication extends Application implements ReactApplication {
@Override
public ReactNativeHost getReactNativeHost() {
  return reactNativeHost;
}}
  1. 所以需要创建一个ReactNativeHost对象给ReactApplication 。这些在继承RN框架的时候也是现成的。不过我们发现RN框架本身似乎还有一些其他的Package要返回,那么我们自己的只要add在后面就可以了。
ReactNativeHost reactNativeHost =new ReactNativeHost(this){
    @Override
    public boolean getUseDeveloperSupport() {
        return false;
    }

    @Override
    protected List<ReactPackage> getPackages() {
       @SuppressWarnings("UnnecessaryLocalVariable")
       List<ReactPackage> packages = new PackageList(this).getPackages();
       // Packages that cannot be autolinked yet can be added manually here, for example:
       // packages.add(new MyReactNativePackage());
      return packages;
    }
};
  1. ReactPackage是接口,我们想要返回自己的ReactPackage就需要实现下这个接口,需要实现的接口里就包括了:createNativeModules
public interface ReactPackage {

  /**
   * @param reactContext react application context that can be used to create modules
   * @return list of native modules to register with the newly created catalyst instance
   */
  @NonNull
  List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext);

  /** @return a list of view managers that should be registered with {@link UIManagerModule} */
  @NonNull
  List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext);
}

  1. 所以就需要一个ReactContextBaseJavaModule交给我们刚刚实现的ReactPackage了。到这终于到了我们要“传递”的工具类出场了。没错,我们的工具类都要定义成“ReactContextBaseJavaModule”以方便RN框架去“传递”。

逻辑基本就是这样了,那么现在开始动手实现吧。
首先,就是改造我们刚才的工具类,因为要RN认识的特殊类才能被“传输”,将刚才的ToastUtil继承下ReactContextBaseJavaModule。多了个需要实现的类:getName

public class ToastUtil extends ReactContextBaseJavaModule {
    private static ReactApplicationContext reactApplicationContext;
    public ToastUtil(@NonNull ReactApplicationContext reactContext) {
        super(reactContext);
        reactApplicationContext=reactContext;
    }

    @ReactMethod
    public void show(String message){
        Toast.makeText(reactApplicationContext, message, Toast.LENGTH_SHORT).show();
    }

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

getName返回一个自定义的字符串,是当前这个工具类的标识符信息。RN应用就是通过这个字符串来找到它想要的工具类的。仔细观察会发现show方法被注解了@ReactMethod,没错,希望在RN中调用的方法都要用这个注解来声明下。这个时候突然发现了一个问题:RN中有Context这个上下文对象吗?再看官网教程,果然直接用了一个传进来的ReactApplicationContext,好吧,还是要传进来并保存下这个ReactApplicationContext留作后用。(你可能会想直接从别的地方拿过来的Context不也行么,结果是不传ReactApplicationContext进来工具类无法正常使用,不仅是你,你实现的ReactContextBaseJavaModule也需要这么一个Contex啊,所以就成了上面这个样子了)
其次,需要实现一个ReactPackage,在它的createNativeModules方法中返回我们的工具类ToastUtil。

public class ToastPackage implements ReactPackage {
    @NonNull
    @Override
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ToastUtil(reactContext));
        return modules;
    }

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

然后需要把我们自己的ReactPackage加到实现了ReactApplication的ReactNativeHost对象的实现方法getPackages里。

@Override
protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
  // Packages that cannot be autolinked yet can be added manually here, for example:
  // packages.add(new MyReactNativePackage());
    packages.add(new ToastPackage());
  return packages;
}

剩下的实现ReactAplication并返回ReactNativeHost的操作一早就已经默认实现了。现在终于把自己定义的工具类交给RN了。

在RN中调用原生方法

我们已经按照RN的要求定义了自己的工具类,并把它交给RN了,RN会帮助我们把这个类“传输”到RN应用中,接下来我们就要尝试在RN应用中来调用了。

import React from 'react';
import {NativeModules, Button, View} from 'react-native';

export default class App extends React.Component {
  _onPress() {
    NativeModules.ToastUtil.show('哈哈');
  }

  render(): React$Node {
    return (
      <View>
        <Button onPress={this._onPress} title={'显示Toast'} />
      </View>
    );
  }
}

从原生传过来的工具类都在NativeModules里,所以我们需要先引入NativeModules。那么怎么定位到具体的我们的工具类呢?还记得实现工具类里继承了一个getName的方法么,之前说它是那个工具类的标识符,现在派上用场了。之前返回的字符串是“ToastUtil”,那么我们的工具类就是: NativeModules.ToastUtil了,可以直接在RN应用中通过

NativeModules.ToastUtil.show('哈哈');

来调到原生的ToastUtil.show(‘哈哈’)方法了。点击按钮就能看到熟悉的Toast了。
在这里插入图片描述
ok,到这入门就结束了。

总结

对于一个init出来的RN项目,快速实现RN对原生方法调用的操作如下:

  1. 创建一个类A继承ReactContextBaseJavaModule,实现的getName返回字符串如“X”,可以使用构造方法获取context,编写自己的要提供给RN的方法y()并使用@ReactMethod注解自定义的方法。
  2. 新建一个类B实现ReactPackage接口,并把上面创建的工具类A在createNativeModules里返回。
  3. 在已经实现了ReactApplication的Application里,找到getReactNativeHost中返回的ReactNativeHost,并在其实现类的getPackages方法中,在返回的List上,增加上面创建的ReactPackage实现类B。
  4. 在RN中import NativeModules from ‘react-native’,并通过NativeModules.X.y()的方式调用原生方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值