惯例这是写在前面的话, 周五的时候和同事朋友聊起来写博客这件事, 自己在朋友圈吹下的牛逼, 无论如何都是要完成的啊, 等把博客写完了, 奖励自己玩一会儿魔兽, 我的小号兽人战士已经 10 级了, 联盟, 你们颤抖吧.
图片发自简书 App
我们这里从
react-natvie 调用原生 android 的方法, 获取原生 android 的数据
部分开始讲, 其中还包括 android 对 react-native 的回调.
这就是说的互相交互的事, 那么我们开始吧!
react-natvie 调用原生 android 的方法, 获取原生 android 的数据
在 react-native 和原生平台 API 之间, 有一个 JavaScript 的桥接层, react-native 就是通过桥接层来和原生的平台进行交互的, 其中, 这涉及到了两个模块 NativeModule 和 NativeEventEmitter.
1.NativeModule: 用于 JavaScript 代码调用原生的代码.
2.NativeEventEmitter: 用于原生代码发送消息到 JavaScript 代码.
我们可以看一下 Animated 下的源码实现:
目录在这里
node_modules\react-native\Libraries\Animated\src\NativeAnimatedHelper.js
它的第一行就是
- const NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
- const NativeEventEmitter = require('NativeEventEmitter');
引用了这两个模块, 我们再看一下下面是怎么调用的呢?
- createAnimatedNode: function(tag: ?number, config: Object): void {
- assertNativeAnimatedModule();
- NativeAnimatedModule.createAnimatedNode(tag, config);
- },
创建一个 Animated 动画, 是通过调用
NativeAnimatedModule.createAnimatedNode(tag, config);
来实现的.
而在 android 这里的代码, 如果想要能够让 react-native 调用到, 需要实现三个步骤:
写出你想要调用的模块 (继承 ReactContextBaseJavaModule)
把这个模块导出 (实现导出接口 ReactPackage)
把这个模块注册发布 (在 MainApplication 中注册)
那么我们开始吧:
1. 写出你想要调用的模块 (继承 ReactContextBaseJavaModule)
- //...
- /**
- * Created by feiyu on 2018/5/12.
- */
- public class CommunicationModule extends ReactContextBaseJavaModule {
- private final ReactApplicationContext mReactContext;
- public CommunicationModule(ReactApplicationContext reactContext) {
- super(reactContext);
- this.mReactContext = reactContext;
- }
- @Override
- public String getName() {
- // 你想要调用的那个模块的名称, 实际上就是当前的这个对象
- return "Communication";
- }
- @Nullable
- @Override
- public Map<String, Object> getConstants() {
- HashMap<String,Object> constants = new HashMap<>();
- constants.put("systemName","android");
- return constants;
- }
- // 我们想要调用的原生的 android 方法, 这个方法可以打开一个 activity, 同时还可以传递参数过来
- @ReactMethod
- public void StartActivityFromReactNative(String activityName, String data, Promise promise, Callback callback){
- Activity currentActivity = getCurrentActivity();
- try{
- if(currentActivity != null){
- Class<?> toActivity = Class.forName("yourPackageName" +"." +activityName);
- Intent intent = new Intent(currentActivity,toActivity);
- intent.putExtra("params",data);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 在 react native 打开 activity
- currentActivity.startActivity(intent);
- }
- promise.resolve(true);
- callback.invoke(true);
- }catch(ClassNotFoundException e){
- throw new JSApplicationIllegalArgumentException("打开 activity 失败"+e.getMessage());
- }
- }
- }
在这里我们实现了一个必须的方法就是 getName 这个方法返回的是我们想要调用的那个模块的名称, 也就是当前对象. 同时我们想要给 react-native 传递一些参数, 就实现了 getConstants 方法, 在这个方法中我们设置了当前平台的名称. 我们想要调用一个 android 本地的方法, 所以我们实现了
StartActivityFromReactNative
方法, 重要的是我们需要设置 @ReactMethod 注解. 调用完
StartActivityFromReactNative
方法后我们想要知道调用结果呢? 我们有两种方式 Promise 和 Callback 都可以, 例如上面的代码.
2. 把这个模块导出 (实现导出接口 ReactPackage)
- //...
- /**
- * Created by feiyu on 2018/5/12.
- */
- public class Communication implements ReactPackage {
- @Override
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
- List<NativeModule> modules = new ArrayList<>();
- modules.add(new CommunicationModule(reactContext));
- return modules;
- }
- @Override
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
- public List<Class<? extends JavaScriptModule>> createJSModules(){
- return Collections.emptyList();
- }
- }
上面的这个就是固定模式了, 你在实现任意的模块时都可以复制上面的代码, 然后把 CommunicationModule 换成你的.
3. 把这个模块注册发布 (在 MainApplication 中注册)
第三步就非常简单了!
- //...
- public class MainApplication extends Application implements ReactApplication {
- private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
- @Override
- protected List<ReactPackage> getPackages() {
- return Arrays.<ReactPackage>asList(
- new MainReactPackage(),
- new Communication()
- );
- }
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
- };
- //...
- }
最后我们在 getPackages 中返回我们的对象就可以了 new Communication().
react-native 调用 android 原生
react-native 调用原生平台是基于 NativeModules, 调用的方法是 NativeModules. 模块名称. 接口名称.
原生平台返回数据到 react-native 平台是基于回调, 回调的原型定义是
RCTRResponseSenderBlock(IOS) 平台
和
- com.facebook.react.bridge.CallBack(Android 平台)
- .
我们想要获取 android 平台定义的那个 systemName 的话只需要这样:
- if(Platform.OS === "android"){
- let systemName = NativeModule.Communction.systemName;
- }
调用我们定义的那个打开 activity 的方法也是同上:
- if(Platform.OS === "android"){
- NativeModule.Communction.StartActivityFromReactNative("CommunicationActivity",123456);
- }
这样就可以了. 然后怎么获取到 react-native 给传过来的数据呢? 在 android 的 activity 中:
- public class CommunicationActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_communication);
- Intent intent = getIntent();
- if(intent != null){
- String params = intent.getStringExtra("'params");
- Toast.makeText(this,"从 react-native 中传递过来的数据"+params,Toast.LENGTH_LONG).show();
- }
- }
- }
需要注意的地方:
1.react native 调用 android 进行界面跳转时, 需要设置
FLAG_ACTIVITY_NEW_TASK
标志
2. 我们在调用 android 的模块时, 名称要和 getName 的方法一样:
NativeModule.Communction.systemName;
就是 Communction...
到这里 react-native 和 android 的就 Over 了. 祝大家周末愉快!
参考书籍:React Native 移动开发实战
来源: http://www.jianshu.com/p/ce845ac1a07c