Android端接口
RN端向Android侧通信可以通过Android侧的接口来实现。
实现接口
Android侧的接口都需要继承ReactContextBaseJavaModule类,如下:
class MyModule extends ReactContextBaseJavaModule {
@NonNull
@Override
public String getName() { return "MyModule"; } // 1
@ReactMethod
public void handleMessage(String msg, Promise pro) { } // 2
}
-
这些类统一都需要实现getName函数,这个函数的用途是返回原生模块代码的名称以供RN模块调用,在RN侧使用这个名称来调用在这个类中定义的函数。
-
想要调用的函数必须要用@ReactMethod关键字将其注释为一个React函数才能在RN侧被调用。
并且这些函数不能有返回值,因为被调用的原生代码是异步执行的。
那么如果我们想要执行完原生的逻辑后想要得到返回值该怎么办呢?我们可以使用异步的方法来做,例如回调函数,Promise, async等。
值得注意的是,即使正确调用了回调函数,这些回调函数也不会立即这些,因为混合开发中的桥接机制是异步的,中间应该用了一个类似于消息队列的机制。
注册模块
在 Android侧要做的最后一件事就是注册这个模块。为此开发者需要实现一个React包管理类。这个类需要继承ReactPackage类。我们需要在这个ReactPackage类的createNativeModules
方法中添加我们实现好的模块。如果模块没有被注册,它也无法在 JavaScript 中被访问到。
class MyPackage extends ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new MyModule(reactContext));
// 这个包管理类的List里可以管理多个module
return modules;
}
}
这个ReactPackage类将在MainApplication.java
的getPackages
方法中被创建一个实例。
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new MyPackage()); // <-- 添加这一行,类名替换成你的Package类的名字 name.
return packages;
}
RN端使用
handleMessage(string msg) {
let { NativeModules } = require('react-native');
NativeModules.handleMessage(msg).then(() => { });
}
注意:如果我们更改了Android项目中的代码,我们需要重新编译Android项目,项目在编译时会中断cmd窗口的监听程序,我们需要再次打开一个cmd运行’react-native start’ 重新开始监听。
跨语言常量
同样的我们可以在Android端通过实现名为getConstants的成员函数来将某些常量暴露给RN侧,这个方法在Android和RN侧需要保持某些常量的一致的时候会有用处。如下:
@Override
public Map<String, Object> getContants() { return MyMap; }
Android侧主动向RN侧发消息
当Android侧需要主动向RN侧发消息时,可以使用消息机制。
// Android侧
MyContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, msg);
// rn侧
DeviceEventEmitter.addListener(eventName, (msg) => { })
注意:使用getJSModule必须要有一个ReactApplicationContext的实例,那么,我们如何获得这个ReactApplication的实例呢?
这里就需要提出一个开发的建议:尽管getJSModule可以在任何位置使用,但是还是建议在ReactContextBaseJavaModule中使用,因为MyModule在创建和注册的时候——createNativeModule 会传递一个ReactApplicationContext,所以创建MyModule的时候可以让构造函数中带上这个参数,这样我们就可以在MyModule中使用ReactApplicationContext了。
Android与RN界面的切换
同样的,我们可以让原生代码初始化一个视图,并且让这个视图获得焦点,这样就实现了RN和原生界面的切换.
初始界面的界定
Android应用初始界面在AndroidManifest.xml文件中进行设置。文件中含有“intent-filter”字段所在的Activity就是默认启动的第一个Activity。
我们可以观察一个项目中被intent-filter标注的Activity,如果这个Activity继承的是ReactActiity,那么这个项目的初始界面就是一个RN界面。
RN向Android的跳转
RN向Android的跳转很简单,与上面接口的实现很类似,只要在需要跳转的时候调用Android端的接口,然后在这个接口中创建intent执行startActivity即可。(//TODO: 可以直接start一个Fragment吗?)
关键在于Android端回到RN端,如果Android不需要传递消息,那么在Android的Activity执行了finish之后就可以回到RN界面,如果需要回传消息,那么就需要在自己实现的ReactContextBaseJavaModule类中实现onActivityResult(),解析出传回来的消息后再使用Promise机制或者消息机制将消息传递给RN端。
Android向原生的跳转
如果初始界面为Android的界面,那么就需要实现从Android向原生的跳转。
Android向RN的跳转不是直接跳转到RN,而是跳转到RN在Android侧的界面容器中。我们需要在Android注册一个ReactActivity假设叫MyReactActivity,当我们需要进行跳转的时候,startActivity就是要启动这个MyReactActivity。
class MyReactActivity extends ReactActivity { }
那么MyReactActivity如何映射到RN界面呢,这就需要在RN端进行注册。如下所示:
// APP.js
import MyComponent from './index.js';
AppRegistry.registerComponent('MyReactActivity', () => MyComponent);