前言
在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统。提到 npm,一般指两层含义:一是 Node.js 开放式模块登记和管理系统,另一种是 Node.js 默认的模块管理器,是一个命令行软件,用来安装和管理 node 模块。本文旨在探讨如何在 React Native 中写一个自定义的 npm 模块(类似于插件),并上传到 npm 上供他人使用。
npm 使用介绍
npm 是一个 Node.js 模块,安装 Node.js 会默认安装 npm,可以在终端中使用以下命令来查看 npm 的版本:
npm -v
升级 npm:
sudo npm install npm -g
安装模块(安装完毕后会产生一个 node_modules 目录,其目录下就是安装的各个 node 模块):
npm install
查看 npm 配置:
npm config list
设置代理:
//设置 http 代理npm config set proxy http://server:port//设置 https 代理npm config set https-proxy http://server:port
上面介绍了一些 npm 基本命令,接下来就可以在本地创建一个模块啦。 首先打开终端中新建一个你想在此创建自定义模块的文件夹,然后在命令行中登录 npm。输入以下命令:
npm adduser
接下来会提示你输入用户名和密码还有邮箱,一一完成后就可以输入以下命令来查看当前 npm 用户了:
npm whoami
如果正确显示了刚才注册的用户名,说明登录成功了。然后就使用以下命令来创建 npm 模块:
npm init
执行上述命令后,会引导你创建一个 package.json 文件,包括名称、版本、作者这些信息等。
创建模块
这里要提一下,为什么要写一个自定义模块。因为 React Native 虽然实现了很多 Native 组件,并且提供了丰富的 API,但是有些原生库还是不支持的,而且有很多开源的组件和库是面向原生的,因此要想在 React Native 中使用这些组件和库就需要自己定义一个模块,这样也方便别人集成。接下来我们直接进入正题。写一个 React Native 中可以使用的自定义模块。在命令行中执行
react-native init AwesomeProject
初始化一个 React Native 项目。这里以 Android 为例,用 Android Studio 选择菜单 File->open 打开 AwesomeProject 文件夹下的 android 文件夹,然后选择 File -> New -> New Module,选择创建一个 Android Library,如图:
如图所示,这里新建了一个 Library module,接下来点击 finish 就可以看到如下的目录结构:
然后将所需要依赖的 jar 放到 libs 目录下,这里以使用 jpush-sdk 为例,将官网上下载的 libs 复制到 libs 下,把相关的资源文件放到 res 文件夹下,再把 AndroidManifest 文件内容复制过来,更改一下包名,最后在 build.gradle 中配置一把,如下(这里要注意把 targetSdkVersion 改成 22,在 23 上运行可能会闪退):
apply plugin: 'com.android.library'android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { minSdkVersion 16 targetSdkVersion 22 versionCode 1 versionName "1.0" manifestPlaceholders = [ JPUSH_APPKEY: "yourAppKey", //在此修改 JPush 的 AppKey APP_CHANNEL: "developer-default" //应用渠道号 ] } lintOptions { abortOnError false warning 'InvalidPackage' } sourceSets { main { jniLibs.srcDirs = ['libs'] } }}repositories { mavenCentral()}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile "com.facebook.react:react-native:+"}
到此为止,我们已经完成了第一步操作,接下来需要写 Native 和 JS 交互的代码,可以参考我的这篇文章中 JS 调用 Native 以及 Native 调用 JS 部分,这里不再赘述。假设我们已经完成了 Native 部分代码,我们如何才能在 JS 中让他人能够通过 import 的方式调用我们的 JS 代码,从而调用 Native 呢?首先进入 my-react-library 文件夹,然后在终端执行
npm init
生成 package.json 文件(注意这里的 name 字段,这里是别人引用你的模块的名字),然后再创建一个 index.js 文件,这是 node 模块的 JS 入口,这里推荐使用 Sublime Text 进行 JS 的编写。这里以 为例:
jpush-react-native/index.js 部分代码
import {NativeModules, Platform, DeviceEventEmitter} from 'react-native';// 通过 NativeModules 找到我们在 Native 定义的 JPushModule 类const JPushModule = NativeModules.JPushModule;export default class JPush { /** * Android only * 初始化 JPush 必须先初始化才能执行其他操作 */ static initPush() { JPushModule.initPush(); }}
上面定义了一个 initPush 方法,initPush 实际上调用了 JPushModule 中定义的 initPush 方法,其他方法与此类似,本质上都是通过 NativeModules 调用了 Native 提供的方法。
发布
到此为止,我们已经完成了 React Native 自定义模块。现在可以发布我们的自定义模块了。在 package.json 所在的目录下执行
npm publish
就可以把我们的自定义模块上传到 npm 库了。每次更新版本时,需要改动 package.json 中的 version 值,然后再执行 npm publish 即可。
使用
在 React Native 目录下,执行:
npm install my-react-library --save
安装完成后就会把这个模块保存到 node_modules 文件夹下,由于我们的模块是一个 Android Library 项目,所以在 Native 中还需要配置一下。主要是添加项目依赖:
someone's react-native project/some module/build.gradle
dependencies { compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules // 在 dependecies 中加入自定义模块 compile project(':my-react-library')}
然后在 settings.gradle 中也要配置一下:
someone's react-native project/settings.gradle
include ':app', ':my-react-library'project(':my-react-library').projectDir = new File(rootProject.projectDir, '../node_modules/my-react-library/android')
在 MainActivity 中将自定义的 Package 添加进去:
MainActivity.java
...mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("react-native-android/index.android") .addPackage(new MainReactPackage())//添加自定义的 package.addPackage(new MyReactPackage())...
如果是 RN 0.29.0 以上版本,则应在 MainApplication 中添加:
MainApplication.java
@Overrideprotected ListgetPackages() { return Arrays. asList( new MainReactPackage(), new MyReactPackage() );}
到此为止我们完成了 Native 部分的配置(完成后 sync 一下),接下来就可以使用了。 别人要使用我们的模块时,就可以这样写:
someone.js
//这里的 'my-react-library'是在 package.json 定义的 name// 这样就可以import MyModule from 'my-react-library'export default class SomeClass extends React.Component { componentDidMount() { // 调用 index.js 中定义的 doSomething() MyModule.doSomething(); }}