bg
开发React Native项目离不开import官方或第三方的组件,这些插件无非都是用吊炸天的(你懂的)
npm管理的。为了为React Native开发社区这个大家庭贡献一点力量,我们也可以自己开发一个组件并发布到npm。
组件发布流程:
下面以组件react-native-app-info为例进行说明组件目标:
提供获取app版本号、名称等信息(兼容iOS和Android)
一、npm 创建组件库
1.安装react-native-create-library
Requirements: Node 6.0+
npm install -g react-native-create-library
2 创建模板项目
创建项目命令:
react-native-create-library [options] <name>
Options:
-h, --help output usage information
-V, --version output the version number
-p, --prefix <prefix> The prefix for the library (Default:RN
)
--module-prefix <modulePrefix> The module prefix for the library (Default:react-native
)
--package-identifier <packageIdentifier> (Android only!) The package name for the Android module (Default:com.reactlibrary
)
--namespace <namespace> (Windows only!) The **namespace for the Windows module
(Default: The name as PascalCase)
--platforms <platforms> Platforms the library will be created for. (comma separated; default:ios,android,windows
)
--github-account <github_account> The github account where the library is hosted (Default:github_account
)
--author-name <name> The author's name (Default:Your Name
)
--author-email <email> The author's email (Default:yourname@email.com
)
--license <license> The license type of this library (Default:Apache-2.0
)
--generate-example <shouldGenerate> Will generate a RN example project and link the new library to it (Default:false
)
注意: android平台必须使用 package-identifier指定包名
2.1创建名为app-info的项目,同时指定android中的package,同时创建example用例项目
$ react-native-create-library --package-identifier com.carrot.appInfo --platforms android,ios --generate-example true app-info
2.2重命名一下项目名
$ mv app-info react-native-app-info
2.3 安装dependencies
终端react-native-app-info下执行:
$ npm install
有人可能会说,楼主为什么不直接生成
react-native-cardview
的项目,而要先生成cardview
再重命名。其实这是一个小技巧,因为利用react-native-create-library
生产的项目,一些跟组件相关的名称或者类会默认加上react-native
或者RN
前缀。
例如,如果你的初始项目名是react-native-card-view
,那么package.json
中定义的组件名将是react-native-react-native-card-view
,android模块中定义的相关类会是RNReactNativeCardviewModule.java
,这显然比较丑啊。
3.tree 命令查看文件目录结构
3.1 Mac OS或者Linux系统不像Windows自带tree工具,需要自己安装 tree:brew install tree
tree命令行 效果
tree -a 显示当前目录树
tree -d 只显示文件夹
tree -D 显示文件的最后修改时间
tree -L n n表示显示项目的层级,n=3即只显示项目的三层结构
tree -I pattern pattern表示想要过滤的目录,例如 tree -I “node_modules”可以过滤掉node_modules这个文件夹
进入到app-info项目根目录下,在命令行输入:
tree -a
目录结构如下:
.
├── .gitattributes
├── .gitignore
├── README.md
├── android
│ ├── build.gradle
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── carrot
│ └── appInfo
│ ├── RNAppInfoModule.java
│ └── RNAppInfoPackage.java
├── index.js
├── ios
│ ├── RNAppInfo.h
│ ├── RNAppInfo.m
│ ├── RNAppInfo.podspec
│ ├── RNAppInfo.xcodeproj
│ │ └── project.pbxproj
│ └── RNAppInfo.xcworkspace
│ └── contents.xcworkspacedata
└── package.json
二、功能实现
注意:
如果你的插件不需要调用原生api(iOS、Android原生功能)进行开发,直接删除ios和android文件夹即可。
如果需要原生配合,也就是需要自定义module的话,就要分别对iOS和Android进行开发了,你可以戳这里React Native自定义原生(iOS和Android)模块Module
1.iOS端实现
iOS端的实现还是很简单的,只需要RNAppInfo.m实现并导出我们的方法就行了。
我们先看一下默认的RNAppInfo.h和RNAppInfo.m文件
#import "RCTBridgeModule.h"
#else
#import <React/RCTBridgeModule.h>
#endif
@interface RNAppInfo : NSObject <RCTBridgeModule>
@end
RNAppInfo.h实现了RCTBridgeModule协议,这就是我们自定义原生module和RN的交互核心所在,这里不详细介绍了,可以戳这里Native Modules
,这样RNAppInfo.m里面导出的方法就可以被RN的js代码调用到了。
这个类主要作用:
1.定义原生模块名,可以直接在javascript中通过NativeModules.xxx
来访问,其中xxx
是在RNxxxModule
类中定义的RCT_EXPORT_MODULE
方法返回值
2.实现并导出我们需要的方法,RCT_EXPORT_METHOD(getAppVersion:(RCTResponseSenderBlock)callback)
3.js就可以通过NativeModules.NativeModules.RNAppInfo. xxx
调用了,xxx是我们导出的方法。
#import "RNAppInfo.h"
@implementation RNAppInfo
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE()
@end
其中,导出模块,不添加参数即默认为这个类名
RCT_EXPORT_MODULE();
1.1导出我们的方法
** 导出方法,桥接到js的方法返回值类型必须是void**
/**
获取app版本号
@param callback:结果回调
*/
RCT_EXPORT_METHOD(getAppVersion:(RCTResponseSenderBlock)callback){
BOOL isSucc = YES;
NSDictionary *info = [self getMainBundle];
NSString* appVersion = info[@"CFBundleShortVersionString"];
//准备回调回去的数据
callback(@[appVersion]);
}
这样我们就实现了iOS端的开发了,没错就是这么简单!!!
2.Android端实现
实现一个android自定义module,你需要关系两个类:RNAppInfoModule.java 、 RNAppInfoPackage.java 、
2.1.1 RNAppInfoModule.java
RNAppInfoModule 集成自 ReactContextBaseJavaModule,原理跟iOS相同。
package com.carrot.appInfo;
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 RNAppInfoModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
public RNAppInfoModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "RNAppInfo";
}
@ReactMethod
/**
* 获取appVersionCode
* @param callback 回调
*/
public static int getVersionCode(Context mContext) {
if (mContext != null) {
try {
return mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return 0;
}
/**
* 获取app版本号
* @param callback 回调
*/
public static String getVersionName(Context mContext) {
if (mContext != null) {
try {
return mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return "";
}
}
这个类主要作用:
1.定义原生模块名,可以直接在javascript中通过NativeModules.xxx来访问,其中xxx是在RNxxxModule类中定义的getName方法返回值
2.实现并导出我们需要的方法:
@ReactMethod
public static String getVersionName(Context mContext) {}
3.js就可以通过NativeModules.NativeModules.RNAppInfo. xxx
调用了,xxx是我们导出的方法,注意:是RNAppInfo不是RNAppInfoModule
三、组件发布
3.1代码上传到github
组件发布到npm的时候需要用到代码的github地址。
方式一、可以先在github上手动创建仓库自己的项目仓库,比如这里是react-native-app-info,
1.git clone "github对应的项目git地址"
2、 cd react-native-app-info
3.git add .
4.git commit -a -m 'init repository'
5. git push -u origin master
方式二、先在github上手动创建仓库react-native-app-info,本地进行关联。
在本地执行以下命令把代码同步到你github对应的repository中:
1、 cd react-native-app-info
2、 git init //初始化本地仓库
3、 git add . //添加要push到远程仓库的文件或文件夹
4、 git commit -m 'init repository'
5、 git remote add origin "github对应的项目git地址" //建立链接远程仓库
6、 git push -u origin master #将本地仓库push到远程仓库
注意:git push 之前还需要编辑.gitignore文件。
在.gitignore中定义哪些文件不进行git管理,也就是不会上传到远程库。
3.2 组件发布到npm registry
开发好组件之后,想在其他的项目(或者提供给其他人安装使用)中通过npm install
的方式安装你的组件,那么你的组件必须发布到npm registry中。
3.2.1 npm registry 设置
npm registry 是什么
简单来说,npm registry就相当于一个包注册管理中心。它管理着全世界的开发者们发布上来的各种插件,同时开发者们可以通过npm install
的方式安装所需要的插件。
npm官方registry为:http://registry.npmjs.org/
国内速度较快的为:https://registry.npm.taobao.org/
查看registry
可以查看当前使用的registry:
$ npm config get registry
切换registry
当然也可以通过命令切换当前使用的npm registry
全局切换
$ npm config set registry http://registry.npmjs.org/
临时指定
有时候你可能只想在执行某些npm命令时临时切换,这个时候,可以使用--registry来指定临时切换的registry,比如在npm发布
$ npm publish --registry http://registry.npmjs.org/
注意:国内目前发布组件时,必须切换为npmjs,否则$ npm publish
也不会成功
3.2.2 创建/登陆npm registry账户
要发布组件到npm registry,你必须要是npm registry的注册用户,通过:
$ npm adduser
来新增一个用户,或者你已经在官网注册了一个用户,可以通过:
$ npm login
来登陆npm registry账户。
利用以下两种方式来确认你是否创建/登陆成功npm registry
- 命令
$ npm whoami
确认本地是否成功登陆认证成功 - 在线打开 https://npmjs.com/~username 查看是否创建账户成功
注意:初次注册、登录npm账号,需要填写邮箱,并进行激活
3.2.3 发布前准备(编写git、npm等配置文件)
编写.gitignore 和 .npmignore文件
- 在.gitignore中定义哪些文件不上传到github中
- 在.npmignore中定义哪些文件发布时不打包
- 如果有.gitignore但是没有.npmignore文件,那么.gitignore可以充当.npmignore的作用
- 具体规则可以参照:npm-developers, .gitignore or .npmignore pattern rules
编写package.json
package.json文件定义了发布的所有信息,包括:组件名、版本、作者、描述、依赖等等关键信息。具体可以参照 Working with package.json
下面是react-native-app-info的package.json文件内容:
{
"name": "react-native-app-info",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"eslint-fix": "npx eslint --fix .",
"lint": "eslint ."
},
"keywords": [
"react-native",
"react-component",
"react-native-component",
"react",
"mobile",
"ios",
"android",
"util",
"app-info",
"app"
],
"repository": {
"type": "git",
"url": "git@https://github.com/rocket-developer/react-native-app-info.git"
},
"author": {
"name": "wanglh",
"email": "zh-app-developer@aerozhonghuan.com"
},
"bugs": {
"url": "https://github.com/rocket-developer/react-native-app-info/issues"
},
"homepage": "https://github.com/rocket-developer/react-native-app-info",
"license": "MIT",
"peerDependencies": {
"prop-types": ">=15.6.2",
"react": ">=16.5.0",
"react-native": ">=0.57.1"
},
"devDependencies": {
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "24.1.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.15.1",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-react": "^7.12.4",
"metro-react-native-babel-preset": "0.46.0"
},
"jest": {
"preset": "react-native",
"testPathIgnorePatterns": [
"/node_modules/"
]
}
}
编写readme.md
可以在readme.md文件中详细说明组件的使用方法、注意事项等。一般使用Markdown语法来编写
编写CHANGELOG.md
记录版本更新及修改记录
以下配置文件不是必须,看自己需求:
编写.eslintrc.js
配置eslint规则
编写.eslintignore
eslint检测忽略文件配置
编写.babelrc
babe配置文件
3.2.3发布组件到npm
做好以上准备之后,就可以发布了。这里需要注意,首次发布跟后面更新发布是不一样的。
首次发布
第一次发布的话,直接执行命令:
$ npm publish
就搞定了,可以在线查看确认是否发布成功。访问链接(<package>是你发布的npm package名):
https://www.npmjs.com/package/<package>
看看是否已经有内容了,有内容说明发布成功了。
更新发布
如果不是首次发布,需要执行两个命令
$ npm version <update_type>
$ npm publish
$ npm version
命令是用来自动更新版本号,update_type
取值有patch
minor
major
。那么在什么场景应该选择什么update_type
呢?看下表
update_type | 场景 | 版本号规则 | 举例 |
---|---|---|---|
- | 首次发布 | 版本号1.0.0 | 1.0.0 |
patch | 修复bug、微小改动时 | 从版本号第3位开始增量变动 | 1.0.0 -> 1.0.1 |
minor | 上线新功能,并且对当前版本已有功能模块不影响时 | 从版本号第2位开始增量变动 | 1.0.3 -> 1.1.3 |
major | 上线多个新功能模块,并且对当前版本已有功能会有影响时 | 从版本号第1位开始增量变动 | 1.0.3 -> 2.0.0 |
注意
如果首次发布版本号不是1.0.0的话,那么用$ npm version <update_type>
来更新会报错,因为你没有按照它约定的版本规则来,这个时候,你可以手动修改package.json
中的version
字段为符合约定规则的版本号,然后直接执行$ npm publish
就可以,然后下次再增量更新的时候,就可以直接使用$ npm version <update_type>
的方式来自动更新版本号了
到此,组件的发布流程就走完了~~
本文参考+推荐:
https://github.com/frostney/react-native-create-library
https://www.jianshu.com/p/091a68ea1ca7