[React Native]原生模块(上)

670 查看

正如上篇文章[React Native]移植原生Android项目中提到,ReactNative目前更多的是用于在原生App中加入一个新的模块。那么,此时如果这个ReactNative模块需要使用到一些原生模块的功能,比如访问平台的API;或者你要复用现成的Java代码;又或者使用Java已经成熟的第三方Library,那么这篇文章会一步步告诉你,如何去调用一个已经封装好的Android原生代码。

实际上,正如上篇文章[React Native]移植原生Android项目中提到,目前更多的还是使用React来做V的工作,那么诸如网络请求之类还是通过在ReactNative模块中调用原生已经封装好的库来实现(据说饿了么目前就是这个方案~)

为了更好的理解,本文演示如何在ReactNative中使用Android平台的Toast功能。

  • 步骤一:新建ReactNative项目

    使用下面的命令新建一个ReactNative项目,确保你的环境已经配置正确,有问题可以参考[React Native]入门篇

    react-native init Demo2

    让我们运行下新建的项目,效果如下


    Paste_Image.png
  • 步骤二:新建原生模块

    用AS开发工具打开Demo2目录下的android项目,新建一个classToastModule继承ReactContextBaseJavaModule,我们的目标是在JS中这样写ToastAndroid.show("Test Toast",ToastAndroid.SHORT),来显示一个Toast

    public class ToastModule extends ReactContextBaseJavaModule {
      public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
      }
    }

    ReactContextBaseJavaModule要求实现getName方法,该方法返回一个String,表示模块的名称,这里返回ToastAndroid

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

    一个可选的方法getConstants,用来封装常量给JS模块使用,比如我们将要用到的常量ToastAndroid.SHORT

    @Override
    public Map<String, Object> getConstants() {
      final Map<String, Object> constants = new HashMap<>();
      constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
      constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
      return constants;
    }

    Java中的方法需要导出才能给JS使用,要导出Java方法,需要使用@ReactMethod来注解,且方法的返回值只能是void

    @ReactMethod
    public void show(String message, int duration) {
      Toast.makeText(getReactApplicationContext(), message, duration).show();
    }

    这样,我们的原生模块已经创建完毕,下面需要注册原生模块了。

  • 步骤三:注册原生模块

    新建一个classMyReactPackager,实现ReactPackager接口,我们需要实现createNativeModules方法,该方法返回所有需要被加载的原生模块。

    public class MyReactPackager implements ReactPackage {
      @Override
      public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> viewManagers = new ArrayList<>();
        viewManagers.add(new ToastModule(reactContext));
        return viewManagers;
      }
    
      @Override
      public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList(); // 返回null会报错
      }
    
      @Override
      public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList(); // 返回null会报错
      }
    }

    我们新建的MyReactPackager,需要在MainActivitygetPackages中注册并返回。

    /**
     * A list of packages used by the app. If the app uses additional views
     * or modules besides the default ones, add more packages here.
     */
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new MyReactPackager() // 这是我们自定义的ReactPackager
      );
    }

    到此原生模块的工作已经告一段落,下面让我们看下如下在ReactNative中调用我们的原生模块。

  • 步骤四:使用原生模块
    打开index.android.js文件,在render方法中用TouchableOpacity封装一个可以点击的视图Text,文本内容为Click to show native Toast

    render() {
      return (
        <View style={styles.container}>
          <TouchableOpacity onPress={this.onPressButton}>
            <Text style={styles.instructions}>
            Click to show native Toast
            </Text>
          </TouchableOpacity>
        </View>
      );
    }

    JS文件中,引入我们步骤二中新建的原生模块ToastAndroid

    var ToastAndroid = require('ToastAndroid');

    TouchableOpacity点击方法为onPressButton,它会调用原生模块导出的show方法。

    onPressButton() {
      ToastAndroid.show('Android Toast', ToastAndroid.SHORT);
    }

    让我们运行下项目,最终效果图如下:


    device-2016-05-19-221758_0-24.gif

本文的源码地址Demo2

下一篇文章会介绍JS调用原生模块的高级用法,敬请期待~