React-Native Native Module In Practise

React-Native 是Facebook 开发的一套移动端跨平台开发的框架,其脱胎于 ReactJS 。React-Native允许你使用JavaScript开发移动端的应用,相对于 PhoneGap React-Native 确实带来了原生应用的性能,如果之前有写过ReactJS,用React-Native开发一个移动端应用是非常容易的。不过虽然React-Native社区一天天壮大,但是仍旧可能需要自己开发一些React-Native的原生模块。

什么是React-Native原生模块

React-Native 模块就是包含原生代码库的React-Native的模块(在Android 里是包含Java代码库,在iOS里是包含Objecive-C/Swift代码库),其工作原理是将原生代码库加载到React-Native的包管理器中,然后用JS通过React-Native的bridge调用原生库里的方法,最后返回结果。

Setup
创建React-Native项目
  1. 创建工作目录mkdir hello-rct
  2. 使用npm init 初始化项目
  3. 使用android sdk自带的cli工具初始化一个android library项目
android create lib-project \
   --name hellorct \                # Project name
   --target android-23 \            # Android SDK version(target)
   --package com.xeodou.hellorct \  # Package name
   --gradle --gradle-version 1.3+ \ # Use gradle and 2.4 later version
   --path android                   # The project's directory

4.在android/build.gradle最后添加

dependencies {
    compile 'com.facebook.react:react-native:0.13.+'
}

5.创建Java组件
添加HelloRCTManager.java

/*
* @Author: xeodou
* @Date:   2015
*/
package com.xeodou.hellorct

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 HelloRCTManager implements ReactPackage {

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new HelloRCT(reactContext));
        return modules;
    }
}

创建HelloRCT.java

/*
* @Author: xeodou
* @Date:   2015
*/

package com.xeodou.hellorct

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

public class HelloRCT extends ReactContextBaseJavaModule {

    public static final String REACT_CLASS = "HelloRCT";

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

    @Override
    public String getName() {
        return REACT_CLASS;         //这里的getName方法是将你的原生模块注册
    }                               //到React-Native的模块包管理器中,然后
                                    //在使用JS使用相同的名字获得该原生模块
    @ReactMethod                    // ReactMethod表明该方法是暴露给JS的
    public void hello(Callback cb) {// 的外部方法,返回一个字符串`Hello RCT`
        cb.invoke("Hello RCT");     // React-Native的调用是异步的
    }                               // 所以这里我们用Callback返回结果
}

6.创建index.android.js

/*
* hello-rct - index.android.js
* Copyright(c) 2015 xeodou <xeodou@gmail.com>
* MIT Licensed
*/

var { NativeModules } = require('react-native');
module.exports = NativeModules.HelloRCT;

7.使用react-native init Example创建一个React-Native的Example应用测试我们的模块

  • 修改Example/settings.gradle
include ':app','hellorct'
project(':hellorct').projectDir = new File(rootProject.projectDir, '../../android')
  • 修改Example/app/build.gradle
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.facebook.react:react-native:0.13.+'
    compile project(':hellorct')  // <- 添加这行
}
  • 修改Example/app/src/main/java/.../MainActivity.java
import com.xeodou.hellorct.HelloRCTManager; //<- import java class

public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
     ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mReactRootView = new ReactRootView(this);

        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .addPackage(new HelloRCTManager())  //<- 注册模块
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();

        mReactRootView.startReactApplication(mReactInstanceManager, "Example", null);

        setContentView(mReactRootView);
    }
...
}

  • 修改Example/index.android.js
...
var { NativeModules } = require('react-native');
var HelloRCT = NativeModules.HelloRCT;

var Example = React.createClass({
  getInitialState: function() {
    return {};
  },
  click: function() {
    HelloRCT.hello( msg => {
      this.setState({
        hello: msg
      })
    })
  },

  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Hi, {this.state.hello}
        </Text>
        <TouchableHighlight onPress={this.click}>
            <Text >Press!</Text>
        </TouchableHighlight>
      </View>
    );
  }
});
...

8.cd Example && react-native run-android

Cheers!!