《React-Native系列》38、 ReactNative混合组件封装

在我们做ReactNative项目的过程中,我们会发现由ReactNative提供给我们的组件或API往往满足不了我们的需求,常常需要我们自己去封装Native组件。

今天我们介绍下如果封装一个简单的ReactNative组件,Native代码采用Android。

需求:实现一个组件、实现类似Android的Toast功能。


1、创建一个RN project

react-native init HybridDemo
如下:
$ react-native init HybridDemo
This will walk you through creating a new React Native project in /Users/birenjie/RN/projects/HybridDemo
Installing react-native package from npm...
Setting up new React Native app in /Users/birenjie/RN/projects/HybridDemo
[email protected] /Users/birenjie/RN/projects/HybridDemo
└── [email protected] 

To run your app on iOS:
   cd /Users/birenjie/RN/projects/HybridDemo
   react-native run-ios
   - or -
   Open /Users/birenjie/RN/projects/HybridDemo/ios/HybridDemo.xcodeproj in Xcode
   Hit the Run button
To run your app on Android:
   Have an Android emulator running (quickest way to get started), or a device connected
   cd /Users/birenjie/RN/projects/HybridDemo
   react-native run-android

2、使用Android Studio打开新建的项目HybridDemo,新建一个空Library

如何新建一个Android的空Library,参考:Android Studio中为项目新建及添加Library

在这里我新建了一个Libray  : rn-toast-android



3、修改rn-toast-android下的build.gradle, 在dependencies中添加compile 'com.facebook.react:react-native:0.20.+'

如下:



4、在Library中新建AndroidToastModule.javaAndroidToastPackage.java

AndroidToastModule.java代码如下:

package com.example.rn_toast_android;

import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.common.MapBuilder;

import java.util.Map;

/**
 * Created by birenjie on 16/10/11.
 */
public class AndroidToastModule extends ReactContextBaseJavaModule {

    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";

    public AndroidToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }


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

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

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


AndroidToastPackage.java代码如下:

package com.example.rn_toast_android;

import com.example.rn_toast_android.AndroidToastModule;
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.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Created by birenjie on 16/10/11.
 */
public class AndroidToastPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(new AndroidToastModule(reactContext));
    }

    //一般情况createJSModules()的返回值都是空集合。
    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    //如果是BaseViewManager或其子类,那么createViewManagers()中返回的就是加入了BaseViewManager的集合
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

5、生成package.json

在....android/rn-toast-android/目录下 执行npm init 

会出现一系列的提示,按照提示完成,最后可以生成package.json 文件



6、测试我们编写的组件

在我们init的项目的根目录(index.android.js)同级目录,新建ToastForAndroid.js

ToastForAndroid.js源码如下:

'use strict';

import React, { Component } from 'react';
import {
  NativeModules,
} from 'react-native';

const {ToastForAndroid}  = NativeModules;


var ToastForAndroidDemo = {

  SHORT: ToastForAndroid.SHORT,
  LONG: ToastForAndroid.LONG,

  show: function (
    message: string,
    duration: number
  ): void {
    ToastForAndroid.show(message, duration);
  },

};

module.exports = ToastForAndroidDemo;


修改index.android.js,如下:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Dimensions,
  TouchableHighlight,
} from 'react-native';


import ToastForAndroid from './ToastForAndroid';

var deviceWidth = Dimensions.get('window').width;
var deviceHeight = Dimensions.get('window').height;

class HybridDemo extends Component {
  render() {
    return (
      <TouchableHighlight  onPress= {()=>ToastForAndroid.show('I am clicked ', ToastForAndroid.LONG)}>
        <Text style={{width:deviceWidth,height:50,backgroundColor:'red',textAlign:'center',textAlignVertical:'center'}}>点击调用Native方法</Text>
      </TouchableHighlight>
    );
  }
}

AppRegistry.registerComponent('HybridDemo', () => HybridDemo);


我们需要修改的MainApplication.java,AndroidToastPackage加入到ReactPackage

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),new AndroidToastPackage()
      );
    }


好,一切准备就绪,我们启动React packager Server。

运行效果如下:



至此,我们自己封装的Android  Toast组件就完成了。


如果我们有npm的镜像服务器,我们还可以把我们的组件发布上去。

在..../android/rn-toast-android/ 目录下执行

$ npm adduser   //增加npm用户
$ npm publish  //上传组件到npm上

这样我们就可以像使用第三方组件一样,使用自己发布的ReactNative混合组件了。


参考:http://blog.csdn.net/zzyyppqq/article/details/50349905




你可能感兴趣的:(ReactNative)