React Native 中的 Android 原生模块
2016-11-22 10:08
591 查看
当使用 React Native 开发 Android 应用时,你可能需要使用没有被 React Native 封装的模块。但你可以使用 Java 编写原生模块,然后选择性的暴露公共接口到 React Native。一起来试一下!
创建一个 Java 类,继承
覆写上述类的
使用
最后,在 Javascript 中通过
让我们一起实践一下。
我们先来引入一个尚未定义的包:
现在我们来编写那个包。我们将会为它创建一个叫
现在我们已经创建了一个包并且包含进
这是一个好的开始,为了 React Native 能从
我们现在有了一个可以被 JavaScript 代码导入的 native 模块,让它做些有趣的事情吧。
这里我们从 React Native 中导入了
在方法体中我们获取当前的 activity,如果没有获取到 activity,就调用 cancel 的回调方法。我们现在有了一个可以运行的方法,但是它还不能做任何有趣的事情。让我们用它打开相册。
首先,我们设置了回调,然后,我们创建了一个
当你调用
首先,我们需要在 react context 中添加 activity event listener:
现在我们可以获取到相册返回的数据了。
在这里我们应该可以通过 success callback 获取到图片 URI。
为了和
原文链接: 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 包含了 ImagePickerIOS 组件,但是在 Android 平台上却没有对应的 ImagePicker 组件。我们接下来就要为 Android 构建一个简单的、和 ImagePickerIOS 大致相仿的 ImagePicker。编写一个 React Native 的 Android 原生模块需要以下步骤:
创建一个ReactPackage,把很多模块(Native 和 Javascript)包含在一起,然后在
MainActivity中的
getPackages方法引用。
创建一个 Java 类,继承
ReactContextBaseJavaModule并实现需要的接口,然后注册到我们的
ReactPackage。
覆写上述类的
getName方法,这个方法会作为 Javascript 的调用方法名。
使用
@ReactMethod注解把需要的公共方法暴露给 Javascript。
最后,在 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 { @Override protected String getMainComponentName() { return "MyApp"; } @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage() ); } }
我们先来引入一个尚未定义的包:
import com.myapp.imagepicker.*; // import the package public class MainActivity extends ReactActivity { @Override protected 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 { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new ImagePickerModule(reactContext)); return modules; } @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public 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 { @ReactMethod public void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) { Activity currentActivity = getCurrentActivity(); if (currentActivity == null) { cancelCallback.invoke("Activity doesn't exist"); return; } } }
这里我们从 React Native 中导入了
Callback和
ReadableMap来对应 JavaScript 中的
function和
object。我们为这个方法加上
@ReactMethod注解,从而使它作为
ImagePicker的一部分被 JavaScript 引用。
在方法体中我们获取当前的 activity,如果没有获取到 activity,就调用 cancel 的回调方法。我们现在有了一个可以运行的方法,但是它还不能做任何有趣的事情。让我们用它打开相册。
public class ImagePickerModule extends ReactContextBaseJavaModule { private static final int PICK_IMAGE = 1; private Callback pickerSuccessCallback; private Callback pickerCancelCallback; @ReactMethod public 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
相关文章推荐
- ReactNative调用Android原生模块
- Android 原生应用嵌入React-Native模块开发-环境配置及填坑记
- React Native调用Android原生模块
- React Native原生模块向JS传递数据的几种方式(Android)
- 关于React-native里Android原生模块和组件的写法
- React Native 中的 Android 原生模块
- [置顶] React-Native开发之原生模块封装(Android)升级版
- ReactNative跟Android原生模块是如何进行数据交互实例
- React Native添加Android原生模块
- Android React Native使用原生模块
- react-native调用Android原生模块
- react native学习笔记25——Android原生模块的封装与调用
- ReactNative调用Android原生模块
- 关于React-native里Android原生模块和组件的写法
- ReactNative 自定义Android原生模块的两种形式
- Android React Native使用原生模块
- React Native Android原生模块开发实战|教程|心得|如何创建React Native Android原生模块
- React-Native开发之原生模块封装(Android)升级版
- react native 学习笔记----将react native嵌入到Android原生应用
- React Native 集成到 Android 原生项目中踩坑记录 (Didn't find class "com.facebook.jni.IteratorHelper")