ReactNative中的Android原生模块

当使用 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。它应该看起来像这样:

 
 
 
  1. package com.myapp; 
  2.  
  3. import com.facebook.react.ReactActivity; 
  4. import com.facebook.react.ReactPackage; 
  5. import com.facebook.react.shell.MainReactPackage; 
  6.  
  7. import java.util.Arrays; 
  8. import java.util.List; 
  9.  
  10. public class MainActivity extends ReactActivity { 
  11.  
  12.     @Override 
  13.     protected String getMainComponentName() { 
  14.         return "MyApp"; 
  15.     } 
  16.  
  17.     @Override 
  18.     protected boolean getUseDeveloperSupport() { 
  19.         return BuildConfig.DEBUG; 
  20.     } 
  21.  
  22.     @Override 
  23.     protected List getPackages() { 
  24.         return Arrays.asList( 
  25.             new MainReactPackage() 
  26.         ); 
  27.     } 
  28. }  

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

 
 
 
  1. import com.myapp.imagepicker.*; // import the package 
  2.  
  3. public class MainActivity extends ReactActivity { 
  4.     @Override 
  5.     protected List getPackages() { 
  6.         return Arrays.asList( 
  7.             new MainReactPackage(), 
  8.             new ImagePickerPackage() // include it in getPackages 
  9.         ); 
  10.     } 
  11. }  

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

 
 
 
  1. package com.myapp.imagepicker; 
  2.  
  3. import com.facebook.react.ReactPackage; 
  4. import com.facebook.react.bridge.JavaScriptModule; 
  5. import com.facebook.react.bridge.NativeModule; 
  6. import com.facebook.react.bridge.ReactApplicationContext; 
  7. import com.facebook.react.uimanager.ViewManager; 
  8.  
  9. import java.util.ArrayList; 
  10. import java.util.Collections; 
  11. import java.util.List; 
  12.  
  13. public class ImagePickerPackage implements ReactPackage { 
  14.     @Override 
  15.     public List createNativeModules(ReactApplicationContext reactContext) { 
  16.         List modules = new ArrayList<>(); 
  17.  
  18.         modules.add(new ImagePickerModule(reactContext)); 
  19.  
  20.         return modules; 
  21.     } 
  22.  
  23.     @Override 
  24.     public List> createJSModules() { 
  25.         return Collections.emptyList(); 
  26.     } 
  27.  
  28.     @Override 
  29.     public List createViewManagers(ReactApplicationContext reactContext) { 
  30.         return Collections.emptyList(); 
  31.     } 
  32. }  

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

创建一个 ReactContextBaseJavaModule

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

 
 
 
  1. package com.myapp.imagepicker; 
  2.  
  3. import com.facebook.react.bridge.ReactContextBaseJavaModule; 
  4.  
  5. public class ImagePickerModule extends ReactContextBaseJavaModule { 
  6.     public ImagePickerModule(ReactApplicationContext reactContext) { 
  7.         super(reactContext); 
  8.     } 
  9. }  

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

 
 
 
  1. @Override 
  2. public String getName() { 
  3.     return "ImagePicker"; 
  4. }  

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

暴露方法

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

 
 
 
  1. import com.facebook.react.bridge.Callback; 
  2. import com.facebook.react.bridge.ReadableMap; 
  3.  
  4. public class ImagePickerModule extends ReactContextBaseJavaModule { 
  5.     @ReactMethod 
  6.     public void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) { 
  7.         Activity currentActivity = getCurrentActivity(); 
  8.      
  9.         if (currentActivity == null) { 
  10.             cancelCallback.invoke("Activity doesn't exist"); 
  11.             return; 
  12.         } 
  13.     } 
  14. }  

这里我们从 React Native 中导入了 Callback 和 ReadableMap 来对应 JavaScript 中的 function 和 object。我们为这个方法加上@ReactMethod 注解,从而使它作为 ImagePicker 的一部分被 JavaScript 引用。

在方法体中我们获取当前的 activity,如果没有获取到 activity,就调用 cancel 的回调方法。我们现在有了一个可以运行的方法,但是它还不能做任何有趣的事情。让我们用它打开相册。

 
 
 
  1. public class ImagePickerModule extends ReactContextBaseJavaModule { 
  2.     private static final int PICK_IMAGE = 1; 
  3.  
  4.     private Callback pickerSuccessCallback; 
  5.     private Callback pickerCancelCallback; 
  6.  
  7.     @ReactMethod 
  8.     public void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) { 
  9.         Activity currentActivity = getCurrentActivity(); 
  10.  
  11.         if (currentActivity == null) { 
  12.             cancelCallback.invoke("Activity doesn't exist"); 
  13.             return; 
  14.         } 
  15.  
  16.         pickerSuccessCallback = successCallback; 
  17.         pickerCancelCallback = cancelCallback; 
  18.  
  19.         try { 
  20.             final Intent galleryIntent = new Intent(); 
  21.  
  22.             galleryIntent.setType("image/*"); 
  23.             galleryIntent.setAction(Intent.ACTION_GET_CONTENT); 
  24.  
  25.             final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image"); 
  26.  
  27.             currentActivity.startActivityForResult(chooserIntent, PICK_IMAGE); 
  28.         } catch (Exception e) { 
  29.             cancelCallback.invoke(e); 
  30.         } 
  31.     } 
  32. }  

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

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

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

 
 
 
  1. public class ImagePickerModule extends ReactContextBaseJavaModule implements ActivityEventListener { 
  2.     public ImagePickerModule(ReactApplicationContext reactContext) { 
  3.         super(reactContext); 
  4.         reactContext.addActivityEventListener(this); 
  5.     } 
  6. }  

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

 
 
 
  1. @Override 
  2. public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { 
  3.     if (pickerSuccessCallback != null) { 
  4.         if (resultCode == Activity.RESULT_CANCELED) { 
  5.             pickerCancelCallback.invoke("ImagePicker was cancelled"); 
  6.         } else if (resultCode == Activity.RESULT_OK) { 
  7.             Uri uri = intent.getData(); 
  8.  
  9.             if (uri == null) { 
  10.                 pickerCancelCallback.invoke("No image data found"); 
  11.             } else { 
  12.                 try { 
  13.                     pickerSuccessCallback.invoke(uri); 
  14.                 } catch (Exception e) { 
  15.                     pickerCancelCallback.invoke("No image data found"); 
  16.                 } 
  17.             } 
  18.         } 
  19.     } 
  20. }  

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

 
 
 
  1. NativeModules.ImagePicker.openSelectDialog( 
  2.   {}, // no config yet  
  3.   (uri) => { console.log(uri) },  
  4.   (error) => { console.log(error) } 
  5. )  

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

网站栏目:ReactNative中的Android原生模块
当前网址:http://www.shufengxianlan.com/qtweb/news1/489001.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联