当使用 React Native 开发 Android 应用时,你可能需要使用没有被 React Native 封装的模块。但你可以使用 Java 编写原生模块,然后选择性的暴露公共接口到 React Native。一起来试一下!

我们要写一个什么东西

在写这篇文章时,React Native 包含了 ImagePickerIOS 组件,但是在 Android 平台上却没有对应的 ImagePicker 组件。我们接下来就要为 Android 构建一个简单的、和 ImagePickerIOS 大致相仿的 ImagePicker。

编写一个 React Native 的 Android 原生模块需要以下步骤:

  1. 创建一个 ReactPackage,把很多模块(Native 和 Javascript)包含在一起,然后在 MainActivity 中的 getPackages 方法引用。
  2. 创建一个 Java 类,继承 ReactContextBaseJavaModule 并实现需要的接口,然后注册到我们的 ReactPackage
  3. 覆写上述类的 getName 方法,这个方法会作为 Javascript 的调用方法名。
  4. 使用 @ReactMethod 注解把需要的公共方法暴露给 Javascript。
  5. 最后,在 Javascript 中通过 NativeModules 导入你的模块。

让我们一起实践一下。

创建一个 ReactPackage

启动 AndroidStudio 并且导航到 MyApp/android/app/src/main/java/com/myapp/MainActivity.java。它应该看起来像这样:

package com.myapp;import com.facebook.react.ReactActivity;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;import java.util.Arrays;
import java.util.List;public class MainActivity extends ReactActivity {@Overrideprotected String getMainComponentName() {return "MyApp";}@Overrideprotected boolean getUseDeveloperSupport() {return BuildConfig.DEBUG;}@Overrideprotected List<ReactPackage> getPackages() {return Arrays.<ReactPackage>asList(new MainReactPackage());}
}

我们先来引入一个尚未定义的包:

import com.myapp.imagepicker.*; // import the packagepublic class MainActivity extends ReactActivity {@Overrideprotected List<ReactPackage> getPackages() {return Arrays.<ReactPackage>asList(new MainReactPackage(),new ImagePickerPackage() // include it in getPackages);}
}

现在我们来编写那个包。我们将会为它创建一个叫 imagepicker 的新目录并且写入 ImagePickerPackage:

package com.myapp.imagepicker;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.Collections;
import java.util.List;public class ImagePickerPackage implements ReactPackage {@Overridepublic List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {List<NativeModule> modules = new ArrayList<>();modules.add(new ImagePickerModule(reactContext));return modules;}@Overridepublic List<Class<? extends JavaScriptModule>> createJSModules() {return Collections.emptyList();}@Overridepublic List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {return Collections.emptyList();}
}

现在我们已经创建了一个包并且包含进 MainActivity 中了。

创建一个 ReactContextBaseJavaModule

我们将会以创建 ImagePickerModule 开始,继承 ReactContextBaseJavaModule

package com.myapp.imagepicker;import com.facebook.react.bridge.ReactContextBaseJavaModule;public class ImagePickerModule extends ReactContextBaseJavaModule {public ImagePickerModule(ReactApplicationContext reactContext) {super(reactContext);}
}

这是一个好的开始,为了 React Native 能从 NativeModules 找到我们的模块,我们需要覆写 getName 方法。

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

我们现在有了一个可以被 JavaScript 代码导入的 native 模块,让它做些有趣的事情吧。

暴露方法

ImagePickerIOS 定义了 openSelectDialog 方法,可以传递配置对象、失败、成功的回调。让我们在 ImagePickerModule 中定义一个相似的方法。

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReadableMap;public class ImagePickerModule extends ReactContextBaseJavaModule {@ReactMethodpublic void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) {Activity currentActivity = getCurrentActivity();if (currentActivity == null) {cancelCallback.invoke("Activity doesn't exist");return;}}
}

这里我们从 React Native 中导入了 CallbackReadableMap 来对应 JavaScript 中的 functionobject。我们为这个方法加上 @ReactMethod 注解,从而使它作为 ImagePicker 的一部分被 JavaScript 引用。
在方法体中我们获取当前的 activity,如果没有获取到 activity,就调用 cancel 的回调方法。我们现在有了一个可以运行的方法,但是它还不能做任何有趣的事情。让我们用它打开相册。

public class ImagePickerModule extends ReactContextBaseJavaModule {private static final int PICK_IMAGE = 1;private Callback pickerSuccessCallback;private Callback pickerCancelCallback;@ReactMethodpublic void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) {Activity currentActivity = getCurrentActivity();if (currentActivity == null) {cancelCallback.invoke("Activity doesn't exist");return;}pickerSuccessCallback = successCallback;pickerCancelCallback = cancelCallback;try {final Intent galleryIntent = new Intent();galleryIntent.setType("image/*");galleryIntent.setAction(Intent.ACTION_GET_CONTENT);final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");currentActivity.startActivityForResult(chooserIntent, PICK_IMAGE);} catch (Exception e) {cancelCallback.invoke(e);}}
}

首先,我们设置了回调,然后,我们创建了一个 Intent 并把它传递给 startActivityForResult。最后,我们把所有的东西都放在 try/catch 块中来处理可能发生的异常。

当你调用 openSelectDialog 时,你应该可以看到一个相册了。然而,当你选择一张图片时,相册并不做任何事情。为了能够处理图片数据,我们需要在模块中处理 activity 的返回值。

首先,我们需要在 react context 中添加 activity event listener:

public class ImagePickerModule extends ReactContextBaseJavaModule implements ActivityEventListener {public ImagePickerModule(ReactApplicationContext reactContext) {super(reactContext);reactContext.addActivityEventListener(this);}
}

现在我们可以获取到相册返回的数据了。

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {if (pickerSuccessCallback != null) {if (resultCode == Activity.RESULT_CANCELED) {pickerCancelCallback.invoke("ImagePicker was cancelled");} else if (resultCode == Activity.RESULT_OK) {Uri uri = intent.getData();if (uri == null) {pickerCancelCallback.invoke("No image data found");} else {try {pickerSuccessCallback.invoke(uri);} catch (Exception e) {pickerCancelCallback.invoke("No image data found");}}}}
}

在这里我们应该可以通过 success callback 获取到图片 URI。

NativeModules.ImagePicker.openSelectDialog({}, // no config yet (uri) => { console.log(uri) }, (error) => { console.log(error) }
)

为了和 ImagePickerIOS 的表现大致相仿,我们可以允许用户选择图片、视频或者直接打开相机。这些功能的写法和上面基本一致,我们将会把它留给读者作为练习。


相关阅读

使用 React Native 构建 Facebook Paper 类似的 UI

作者往期佳作

ES6 Generators 工作原理


作者信息

原文作者: Ryan Linton
原文链接: http://t.cn/Rfadv1R
翻译自MaxLeap团队_前端研发人员:Henry Bai
MaxLeap技术博客首发:https://blog.maxleap.cn/
欢迎关注公众号:MaxLeap_yidongyanfa


活动预告


主题:手把手教你玩转微信小程序,领先进入蓝海市场
时间:11月23日
地点:上海徐汇宜山路888号21楼
报名url:http://t.cn/RfcM3Sa

React Native 中的 Android 原生模块相关推荐

  1. 如何在React Native中写一个自定义模块

    前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...

  2. 如何在 React Native 中写一个自定义模块

    前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...

  3. Android之React Native平台与Android本地模块之间的调用

    Native 模块(Android)          有时候APP需要做出React Native平台没有的功能,你也许会想用一些存在的java代码去解决问题,而不是用javascript脚本去去解 ...

  4. React Native开发指南-在原生和React Native间通信

    通过植入原生应用和原生UI组件两篇文档,我们学习了React Native和原生组件的互相整合.在整合的过程中,我们会需要在两个世界间互相通信.有些方法已经在其他的指南中提到了,这篇文章总结了所有可行 ...

  5. React Native Android原生模块开发实战|教程|心得|怎样创建React Native Android原生模块...

    尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691503) 告诉大家一个好消息. ...

  6. Android之React Native 中组件的生命周期

    React Native 中组件的生命周期 概述 就像 Android 开发中的 View 一样,React Native(RN) 中的组件也有生命周期(Lifecycle).所谓生命周期,就是一个对 ...

  7. android 倒计时封装,react native中的聊天气泡及timer封装成的发送验证码倒计时

    其实,今天我想把我近期遇到的坑都总结一下: 1.goBack的跨页面跳转,又两种方法,一可以像兔哥那样修改navigation源码,二可以用navigationActions 2.父子组件的传值,一可 ...

  8. 【云原生】在 React Native 中使用 AWS Textract 实现文本提取

    ⭐️ 本文首发自 前端修罗场(点击加入),一个专注 Web 技术.答疑解惑.面试辅导.职业发展的社区.现在加入,即可参与打卡挑战,和一群人一起努力.挑战成功即可获取一次免费的模拟面试机会,进而评估知识 ...

  9. uniapp android原生,在uni-app项目中集成Android原生工程

    [TOC] # 在uni-app项目中集成Android原生工程 按照官方的方案,我们如果进行本地打包的话,需要重新创建一个Android原生工程,于是就会导致我们管理多个项目,切来切去的也麻烦. 经 ...

最新文章

  1. linux安装中文环境,[Linux]Ubuntu 7.04 中文环境的安装
  2. Android’s PreferenceActivity for all API versions
  3. lcx源代码以及免杀的研究
  4. 又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)
  5. oracle数据同步异常,案例:DataGuard同步异常问题处理记录
  6. Oracle删除用户与删除表
  7. 排球计分程序功能说明书
  8. linux cpu 工作频率,Linux系统限制CPU工作频率(示例代码)
  9. (tensorflow2.1.0安装教程) 对应Anaconda3(对应python3.7)+cuda10.1+cudnn7.6.5+Pycharm 网盘 链接
  10. 《Java从入门到放弃》JavaSE入门篇:练习——单身狗租赁系统
  11. swagger配置及注解详解
  12. 汇编语言典型例子详解_汇编语言程序设计例子
  13. Kali [CobaltStrike]CS神器
  14. 中国极地考察船“雪龙”号在南极碰撞冰山 目前人船安全
  15. MySQL语法练习---常见题型练习
  16. gpio控制和相关操作
  17. 汽车雨刷器的保养细则
  18. journalctl中文手册
  19. 【优化求解-单目标求解】基于黑猩猩算法求解单目标问题matlab源码
  20. JSON字符串转换为JSON对象 互转函数

热门文章

  1. 配电自动化终端安防改造用配电加密模块(产品已经在10KV线路上数千台配电自动化终端进行过安防改造)...
  2. 1G1C 的云服务器能干嘛
  3. html5交互式地铁线路图,HTML5 SVG城市地铁路线图动画演示
  4. excel根据数据画饼状图等
  5. 只用1年时间,机械品牌在国际电焊界名声大噪,看他是如何玩转kol网红营销的
  6. 什么是“首次NFT发售(INO)”?
  7. 计蒜之道2019 复赛 D-星云系统(单调栈)
  8. arXiv每日推荐-5.5:语音/音频每日论文速递
  9. 详细解读【文件系统】
  10. 视频通话 - 时信魔方教程