Write Android Component for React Native / 编写React Native自定义Android组件

Posted by Pengyu on November 1, 2017

之前写过一篇如何在React Native下用Objective-C编写iOS组件的博文,本篇文章简单介绍一下如何编写Android的React Native组件。

本篇以React Native官方文档Native Modules为基础,从零开始介绍如果编写基于React Native的Android的Toast组件。

1 - 准备工作

  • Android Studio
  • React Native CLI
npm install -g react-native-cli

2 - 创建React Native Bridge Module - ToastDemo

文件结构如下:

--Project Folder

|–package.json |–android //这个文件夹内包含我们所需要的Java的原生代码 |–index.js


接下来我们分别来编写、生成这些文件。

Package.json

创建一个新的文件夹叫react-native-toast-demo,它也是你的模块的名称。下面我们进行初始化该项目:

cd react-native-toast-demo
npm init

根据命令行提示一路回车键使用默认值即可,当然你也可以进行初始化赋值或之后到文件中修改都可以。

~$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (react-native-toast-demo)
version: (1.0.0)
description: Toast Demo for React Native Android
entry point: (index.js)
test command:
git repository:
keywords: react native, android, toast, demo
author: shongsu
license: (ISC) MIT
About to write to ~/react-native-toast-demo/package.json:

{
  "name": "react-native-toast-demo",
  "version": "1.0.0",
  "description": "Toast Demo for React Native Android",
  "main": "index.js",
  "scripts": {

“test”: “echo "Error: no test specified" && exit 1”

},
"keywords": [

“react”, “native”, “android”, “toast”, “demo”

  ],
  "author": "shongsu",
  "license": "MIT"
}


Is this ok? (yes) yes

到现在为止,我们的package.json文件就已经生成成功了。

Android

接下来到了创建Android项目的时候了,首先建立一个简单的Android项目结构目录。结构大体如下:

--react-native-toast-demo/android

|–build.gradle |–src

|--main
    |--AndroidManifest.xml
    |--java
         |--com
             |--shongsu
                   |--toastdemo
                        |--DemoModule.java
                        |--DemoPackage.java

  • build.gradle
apply plugin: 'com.android.library'

android {

compileSdkVersion 23 buildToolsVersion “25.0.0”


defaultConfig {

minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"

}

}

dependencies {

compile “com.facebook.react:react-native:+”

}
  • AndoridManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package=”com.shongsu.toastdemo”>

</manifest>
  • DemoModule.java
package com.shongsu.toastdemo;

import android.widget.Toast;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class DemoModule extends ReactContextBaseJavaModule {

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


@Override public String getName() { return “DemoModule”; }


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

}

DemoModule继承了ReactContextBaseJavaModule类并实现了JavaScript所需要的方法。 在这里,getName()返回的字符串必须和你的类名相同

  • DemoPackage.java

DemoPackage.java是用来注册模块的。

package com.shongsu.toastdemo;

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 com.shongsu.toastdemo.DemoModule;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class DemoPackage implements ReactPackage {

public List<Class<? extends JavaScriptModule» createJSModules() { return Collections.emptyList(); }


@Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); }


@Override public List createNativeModules(

ReactApplicationContext reactContext) {

List modules = new ArrayList<>();


modules.add(new DemoModule(reactContext));


return modules; }


}

Index.js

接下来我们来创建index.js文件,该文件是用来将React Native的模块封装成JavaScript的模块的。

import {NativeModules} from 'react-native';
module.exports = NativeModules.DemoModule;

至此,我们完成了这个React Native的模块。

Example

创建一个React Native项目

react-native init Example

由于所有的Node模块都必须安装在{React Native project}\node_modules\目录下,所以我们需要将插件的相对路径写入React Native项目的package.json中,以保证项目能够正确找到插件文件。

添加后的Example/package.json代码如下:

"dependencies": {
"react": "16.0.0-beta.5",
"react-native": "0.49.5",
"react-native-toast-demo":"../"

},


然后通过npm安装模块:

cd Example
npm install

接下来链接依赖项:

react-native link

App.js中使用我们的自定义组件:

import React, { Component } from 'react';
import {

Platform, StyleSheet, Text, View, Button

} from 'react-native';
import DemoModule from 'react-native-toast-demo';

const onButtonPress = () => {

DemoModule.alert(‘Hello World’);

};

export default class App extends Component<{}> {

render() { return (

<View style={styles.container}>
  <Button title='Click' onPress={onButtonPress}/>
</View>

); }

}

const styles = StyleSheet.create({

container: { flex: 1, justifyContent: ‘center’, alignItems: ‘center’, backgroundColor: ‘#F5FCFF’, }

});

然后运行项目即可。

项目代码的Github链接