大纲
- 为什么需要 React Native Module
- 如何创建一个 React Native的模块
- 编写 Android Toast 功能模块
- 如何调试 React Native 模块---------官方文档中未提及或者我没有找到,这里是我自己探索的
- npm 发布一个 React Native 模块(外链接)
为什么需要 React Native Module
各位使用 React Native 时候是否会有碰到仅用React Native 提供的现有API 无法实现的功能。如微信登录、微信/支付宝支付,访问App的数据库SQLite,还有针对性能的提升等等。这些东西在使用React Native 现有的功能无法实现的时候,将需要开发React Native Moduel。当然也可以使用社区中第三方库,这些三方库也是 React Native Module 。
总之,React Native Module 是可以给JS层扩展一些新的功能,这些功能是现有React Native API无法实现的功能,需要与原生代码进行交互的部分。
如何创建一个 React Native的模块
通过官方文档的查阅和学习,知道可以使用 react-native-create-library
这个库来快速创建一个包含Android ,IOS,Windows 系统下的模块,这个模块并且可以直接使用react-native link
快速链接到现有的 React Native 的应用中。
下面将简单介绍如何安装使用 react-native-create-library。
- 安装 react-native-create-library
# npm
npm install -g react-native-create-library
# yarn
yarn add -g react-native-create-library
- 创建一个 React Native Module 模块
# 这样将创建一个具有 Android ios windows 3个模块的 React Native Module
react-native-create-library demo
# 这样将仅创建一个具有 Android ios 2个模块的 React Native Module
react-native-create-library demo --platforms android,ios
上面就是创建一个React Native Module 的简单介绍,更多关于 react-native-create-library 的使用请移步GitHub官方仓库。
编写 Android Toast 功能模块
这里是参考官网【Android 原生模块】,可以点击查看详情,下面是简单介绍。
- 所有的Android 原生模块都是继承于ReactContextBaseJavaModule类。
- ReactContextBaseJavaModule.getName 方法是将当前这个模块暴露给JavaScript层的名字
- ReactContextBaseJavaModule.getContants 返回的Map对象,是暴露给JavaScript层的一些常量
- 在ReactContextBaseJavaModule类中使用
@ReactMethod
注解导出一个方法给JavaScript
// 这是上面几个步骤的共同代码
// 这里定义一个类继承 ReactContextBaseJavaModule
public class RNToastModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
public RNToastModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
/**
* 这里导出的字符串为当前模块的 JS 名称
* 在js中获取到当前模块中如下获取到当前模块:
* NativeModules.RNToast
* NativeModules 为 import { NativeModules } from 'react-native'; 中的 NativeModules
* @return
*/
@Override
public String getName() {
return "RNToast";
}
/**
* 这里返回的值会被JS模块当做常量来使用
* 使用方式为
*
* NativeModules.RNToast.SHORT === Toast.LENGTH_SHORT
* NativeModules.RNToast.LONG === Toast.LENGTH_LONG
*
* @return
*/
@Nullable
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("SHORT", Toast.LENGTH_SHORT);
constants.put("LONG", Toast.LENGTH_LONG);
return constants;
}
/**
* 这里暴露一个方法给 React Native
*
* 在JS中使用方式为:
*
* NativeModules.RNToast.show(msg, duration); // duration 可以使用上面 getConstants 方法暴露出来的常量
*
* @param msg
* @param duration
*/
@ReactMethod
public void show( String msg, int duration ){
Toast.makeText(getReactApplicationContext(), msg, duration).show();
}
}
- 封装一个JavaScript模块
import { NativeModules } from "react-native";
// 下一句中的ToastExample即对应上文
// public String getName()中返回的字符串
export default NativeModules.RNToast;
经过上面几个简单的步骤就开发好了一个 React Native Module 模块,但是这里有一个重要的问题,开发的React Native Module 不可能每个都像Toast这个模块如此简单,应该如何在开发的过程中调试是一个重要的问题,不可能每次都发布到npm上来进行调试,每次发布调试也将影响他人正常使用该模块,而且也给开发带来了非常多不必要的麻烦,因此需要一个非常有效的调试方式,接下来将介绍如何调试React Native 模块。
如何调试 React Native 模块
基本思路为:既然是要调试 React Native 模块,就需要一个 React Native App,然后将自己写的React Native Module模块导入React Native App 中,并且启动App,修改Module,再次安装调试,这样一系列的操作。具体步骤如下:
- 创建 React Native App
# 创建一个名为 toast_demo 的工程
react-native init toast_demo
# 等待命令的执行,执行完后安装依赖,启动服务,安装app到模拟器或者真机,这样完成了一个react native app的创建
- 将 React Native Module 模块导入现有的App
# 先在 toast 工程中, yarn link 命令可以将toast工程导入全局,
# 在别的工程中使用yarn link react-native-toast 就可以使用当前的toast工程
# 为什么是 react-native-toast 而不是 toast,可以点开 toast > package.json文件
# 将会发现 toast 工程的 name 是 react-native-toast,
# 前缀 react-native 是由 react-native-create-library 加上的。
# 因此这里是 react-native-toast 而不是 toast。
yarn link
# 在 toast_demo 工程中敲击yarn link react-native-toast,
# 再点开 toast_demo 工程下的node_modules 会发现 react-native-toast被
# 加载到toast_demo/node_modules里面了
yarn link react-native-toast
# react-native link 命令不用多说
react-native link react-native-toast
上面的事情都做完了你很开心的启动你的工程,并安装到手机上调试的时候会发现下面这个问题(unable to resolve module 'react-native-toast')
这个问题主要导致的原因是React Native工程不支持 symlinks。怎么解决这个问题呢?
这里使用 haul , 这是一个用于开发 React Native App 的命令行工具。它可以很好的使用 Webpack 生态,以及支持热更新,不用每修改等待React Native 来重新编译,当然它也支持 symlinks ,所以可以使用 haul 来解决上面遇到的这个问题,具体使用方式可以查看官方 GitHub仓库,下面是简单介绍:
# 安装 haul
yarn add --dev haul
# 初始化 haul和安装haul的依赖,但是npx 不会准确的安装所有的依赖,因此在使用haul的时候可能会提示漏掉了某些库,
# 只要根据提示安装完所有的依赖即可
yarn haul init
# npm >= 5.2.0 :
npx haul init
# npm < 5.2.0 :
npm install -g npx
npx haul init
# 然后启动 haul 相关服务
yarn haul start --platform ios
# Or:
npx haul start --platform ios
我是使用 haul^1.0.0-rc.15 这个版本的 haul,会碰到这个issue中的问题,haul的作者有提供解决方案,修改haul.config.js
为一下内容。
import { createWebpackConfig } from "haul";
export default {
webpack: env => {
const config = createWebpackConfig({
entry: './index.js',
})(env);
config.module.rules.some(rule => {
if (rule.test && rule.test.source.includes('js')) {
rule.use = [
{
loader: require.resolve('babel-loader'),
options: {
presets: [['module:metro-react-native-babel-preset', { enableBabelRuntime: false }]],
plugins: [require.resolve('haul/src/utils/fixRequireIssues')],
},
},
];
return true;
}
});
return config;
}
};
然后重新启动 haul, 将能够正常的运行React Native App 了。
修改 Android Studio 中 react-native-toast 中的代码将会直接映射到 toast 工程中,这是 symlinks 的功能,这个功能非常的方便调试和修改module。
(官方文档中未提及调试这块或者我没有找到,这里是我自己探索的,有更好的方式请各位告知)
开发好一个module,希望别人可以使用或者自己在下次工程中使用,这该怎么办呢?当然是将当前的react native module 发布到 npm 上,怎么发布请继续往下看。
npm 发布一个 React Native 模块(外链接)
这是其他博主写的npm包的创建和发布流程,主要使用 npm publish来发布和更新一个npm包,发布的npm包他人将可以使用npm或者yarn 进行下载和安装使用你写的模块。
以上就是开发一个 React Native Android Module 的过程,如果是IOS也可以类比这个流程来开发调试。
toast 工程样例
toast_demo 工程样例
【参考】
- Native Modules Setup
- React Native 中文官方文档 Android 原生模块
- React Native: npm link local dependency, unable to resolve module
- haul - Attempted to assign to readonly property