在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统。提到 npm,一般指两层含义:一是 Node.js 开放式模块登记和管理系统,另一种是 Node.js 默认的模块管理器,是一个命令行软件,用来安装和管理 node 模块。本文旨在探讨如何在 React Native 中写一个自定义的 npm 模块(类似于插件),并上传到 npm 上供他人使用。
npm 是一个 Node.js 模块,安装 Node.js 会默认安装 npm,可以在终端中使用以下命令来查看 npm 的版本:
npm -v
升级 npm:
sudo npm install npm -g
安装模块(安装完毕后会产生一个 node_modules 目录,其目录下就是安装的各个 node 模块):
npm install <ModuleName>
查看 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,如图:
然后将所需要依赖的 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 为例:
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 List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>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();
}
}
作者:KenChoi - 极光( JPush 为极光推送团队账号,欢迎关注)
知乎专栏:极光日报
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.