新技术论坛
搜索
查看: 1090|回复: 0
打印 上一主题 下一主题

[Android] React Native中的Android原生模块

[复制链接]
  • TA的每日心情
    开心
    2016-12-9 18:18
  • 签到天数: 85 天

    连续签到: 1 天

    [LV.6]常住居民II

    扫一扫,手机访问本帖
    楼主
    跳转到指定楼层
    发表于 2016-11-24 06:27:31 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式


      当使用 React Native 开发 Android 应用时,你可能需要使用没有被 React Native 封装的模块。但你可以使用 Java  编写原生模块,然后选择性的暴露公共接口到 React Native。一起来试一下!
      我们要写一个什么东西
      在写这篇文章时,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。它应该看起来像这样:
    1. package com.myapp;

    2. import com.facebook.react.ReactActivity;
    3. import com.facebook.react.ReactPackage;
    4. import com.facebook.react.shell.MainReactPackage;

    5. import java.util.Arrays;
    6. import java.util.List;

    7. public class MainActivity extends ReactActivity {

    8.     @Override
    9.     protected String getMainComponentName() {
    10.         return "MyApp";
    11.     }

    12.     @Override
    13.     protected boolean getUseDeveloperSupport() {
    14.         return BuildConfig.DEBUG;
    15.     }

    16.     @Override
    17.     protected List<ReactPackage> getPackages() {
    18.         return Arrays.<ReactPackage>asList(
    19.             new MainReactPackage()
    20.         );
    21.     }
    22. }  
    复制代码

      我们先来引入一个尚未定义的包:
    1. import com.myapp.imagepicker.*; // import the package

    2. public class MainActivity extends ReactActivity {
    3.     @Override
    4.     protected List<ReactPackage> getPackages() {
    5.         return Arrays.<ReactPackage>asList(
    6.             new MainReactPackage(),
    7.             new ImagePickerPackage() // include it in getPackages
    8.         );
    9.     }
    10. }  
    复制代码

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

    2. import com.facebook.react.ReactPackage;
    3. import com.facebook.react.bridge.JavaScriptModule;
    4. import com.facebook.react.bridge.NativeModule;
    5. import com.facebook.react.bridge.ReactApplicationContext;
    6. import com.facebook.react.uimanager.ViewManager;

    7. import java.util.ArrayList;
    8. import java.util.Collections;
    9. import java.util.List;

    10. public class ImagePickerPackage implements ReactPackage {
    11.     @Override
    12.     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    13.         List<NativeModule> modules = new ArrayList<>();

    14.         modules.add(new ImagePickerModule(reactContext));

    15.         return modules;
    16.     }

    17.     @Override
    18.     public List<Class<? extends JavaScriptModule>> createJSModules() {
    19.         return Collections.emptyList();
    20.     }

    21.     @Override
    22.     public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    23.         return Collections.emptyList();
    24.     }
    25. }  
    复制代码

      现在我们已经创建了一个包并且包含进 MainActivity 中了。
      创建一个 ReactContextBaseJavaModule
      我们将会以创建 ImagePickerModule 开始,继承 ReactContextBaseJavaModule。
    1. package com.myapp.imagepicker;

    2. import com.facebook.react.bridge.ReactContextBaseJavaModule;

    3. public class ImagePickerModule extends ReactContextBaseJavaModule {
    4.     public ImagePickerModule(ReactApplicationContext reactContext) {
    5.         super(reactContext);
    6.     }
    7. }  
    复制代码

      这是一个好的开始,为了 React Native 能从 NativeModules 找到我们的模块,我们需要覆写 getName 方法。
      @Override public String getName() {     return ImagePicker; }  
      我们现在有了一个可以被 JavaScript 代码导入的 native 模块,让它做些有趣的事情吧。
      暴露方法
      ImagePickerIOS 定义了 openSelectDialog 方法,可以传递配置对象、失败、成功的回调。让我们在  ImagePickerModule 中定义一个相似的方法。
    1. import com.facebook.react.bridge.Callback;
    2. import com.facebook.react.bridge.ReadableMap;

    3. public class ImagePickerModule extends ReactContextBaseJavaModule {
    4.     @ReactMethod
    5.     public void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) {
    6.         Activity currentActivity = getCurrentActivity();
    7.      
    8.         if (currentActivity == null) {
    9.             cancelCallback.invoke("Activity doesn't exist");
    10.             return;
    11.         }
    12.     }
    13. }  
    复制代码

      这里我们从 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.     private Callback pickerSuccessCallback;
    4.     private Callback pickerCancelCallback;

    5.     @ReactMethod
    6.     public void openSelectDialog(ReadableMap config, Callback successCallback, Callback cancelCallback) {
    7.         Activity currentActivity = getCurrentActivity();

    8.         if (currentActivity == null) {
    9.             cancelCallback.invoke("Activity doesn't exist");
    10.             return;
    11.         }

    12.         pickerSuccessCallback = successCallback;
    13.         pickerCancelCallback = cancelCallback;

    14.         try {
    15.             final Intent galleryIntent = new Intent();

    16.             galleryIntent.setType("image/*");
    17.             galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    18.             final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");

    19.             currentActivity.startActivityForResult(chooserIntent, PICK_IMAGE);
    20.         } catch (Exception e) {
    21.             cancelCallback.invoke(e);
    22.         }
    23.     }
    24. }  
    复制代码

      首先,我们设置了回调,然后,我们创建了一个 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.             if (uri == null) {
    9.                 pickerCancelCallback.invoke("No image data found");
    10.             } else {
    11.                 try {
    12.                     pickerSuccessCallback.invoke(uri);
    13.                 } catch (Exception e) {
    14.                     pickerCancelCallback.invoke("No image data found");
    15.                 }
    16.             }
    17.         }
    18.     }
    19. }  
    复制代码

      在这里我们应该可以通过 success callback 获取到图片 URI。
    1. NativeModules.ImagePicker.openSelectDialog(
    2.   {}, // no config yet  
    3.   (uri) => { console.log(uri) },  
    4.   (error) => { console.log(error) }
    5. )  
    复制代码

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


    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    手机版|Archiver|开发者俱乐部 ( ICP/ISP证:辽B-2-4-20110106号 IDC证:辽B-1-2-20070003号 )

    GMT+8, 2025-1-4 15:51 , Processed in 0.110014 second(s), 21 queries .

    X+ Open Developer Network (xodn.com)

    © 2009-2017 沈阳讯网网络科技有限公司

    快速回复 返回顶部 返回列表