原文链接:https://www.jianshu.com/p/091a68ea1ca7

写在前面

在做react-native开发的时候,我们经常会找到一些第三方组件,并且通过npm install的方式很方便的安装使用。在使用的同时,你是否想过,我们自己应该如何开发并发布一个组件呢?不管是给自己的多个项目共用,或者开源给到别人用,这都是一件很酷的事情。

那么今天,我就以我自己开发的一个在iosandroid通用的CardView组件为例来讲一下,如何开发一个自己的组件,并开源到github、发布到npm上去

一个说明

我的组件名为react-native-rn-cardview。教程里如果出现react-native-cardview组件名,视为同一意思。

1 创建并实现

1.1 创建自定义组件模版项目

1.1.1 安装react-native-create-library

$ npm install -g react-native-create-library

1.1.2 创建模板项目

我们用命令react-native-create-library创建项目,并指定平台为ios,android,指定android中的package,其他参数可以自行参考在react-native-create-librarygithub 上的文档说明,这里就不赘述

$ react-native-create-library --package-identifier com.quenice.cardview --platforms android,ios cardview

我们重命名一下项目名

$ mv cardview react-native-cardview

有人可能会说,楼主为什么不直接生成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,这显然比较丑啊。

ok, 我们继续。

现在的目录结构:

$ tree
└── react-native-cardview
├── README.md
├── android
│ ├── build.gradle
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── reactlibrary
│ ├── RNCardviewModule.java
│ └── RNCardviewPackage.java
├── index.js
├── ios
│ ├── RNCardview.h
│ ├── RNCardview.m
│ ├── RNCardview.podspec
│ ├── RNCardview.xcodeproj
│ │ └── project.pbxproj
│ └── RNCardview.xcworkspace
│ └── contents.xcworkspacedata
└── package.json

生成好组件项目后,就可以开始编写实现代码了

2 编写代码

编写代码分为三部分,一部分是android原生代码,一部分是iOS原生代码,一部分是react-native(或者javascript)代码。由于react-native-cardview只涉及到android原生模块,所以本篇文章暂不涉及到iOS原生模块开发,如果大家感兴趣,我可以另开一篇文章专门讲一下iOS原生模块相关内容

2.1 编写Android Native Module

编写android原生代码,一般以下三个类是必须的:

2.1.1 RNxxxModule

这个类主要作用是定义原生模块名,可以直接在javascript中通过React.NativeModules.xxx来访问,其中xxx是在RNxxxModule类中定义的getName方法返回值。以下为我组件react-native-cardview中的Module类

RNCardViewModule.java

package com.quenice.reactnative;

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 RNCardViewModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; public RNCardViewModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
} @Override
public String getName() {
return "RNCardView";
}
}

2.1.2 RNxxxManager

Manager类主要是组件的原生实现,并且把react-native组件的属性映射到原生属性

RNCardViewManager.java

package com.quenice.reactnative;

import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.view.View; import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.view.ReactViewGroup; public class RNCardViewManager extends ViewGroupManager<CardView> {
@Override
public String getName() {
return "RNCardView";
} @Override
protected CardView createViewInstance(ThemedReactContext reactContext) {
CardView cardView = new CardView(reactContext);
cardView.setUseCompatPadding(true);
cardView.setContentPadding(0, 0, 0, 0);
ReactViewGroup reactViewGroup = new ReactViewGroup(reactContext);
cardView.addView(reactViewGroup);
return cardView;
} @ReactProp(name = "cardElevation", defaultFloat = 0f)
public void setCardElevation(CardView view, float cardElevation) {
view.setCardElevation(PixelUtil.toPixelFromDIP(cardElevation));
}
...
}

2.1.3 RNxxxPackage

Package类主要用于注册原生模块、原生组件实现,也就是注册上面的Module和Manager类

RNCardViewPackage.java

package com.quenice.reactnative;

import java.util.Arrays;
import java.util.Collections;
import java.util.List; import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;
public class RNCardViewPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNCardViewModule(reactContext));
} // Deprecated from RN 0.47
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
} @Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(new RNCardViewManager());
}
}

2.2 编写iOS原生代码

react-native-cardview
iOS的实现方式直接利用react-nativeshadow相关属性就可以实现,所以本文暂不涉及

2.3 编写ReactNative代码

编写好了android/iOS原生模块后,需要编写javascript代码来桥接react-native与原生模块。

RNCardView.android.js

import PropTypes from 'prop-types';
import {requireNativeComponent, View} from 'react-native'; const iface = {
name: 'CardView',
propTypes: {
cardElevation: PropTypes.number,
maxCardElevation: PropTypes.number,
backgroundColor: PropTypes.string,
radius: PropTypes.number,
...View.propTypes, // include the default view properties
},
}; module.exports = requireNativeComponent('RNCardView', iface);

3 代码上传与组件发布

3.1 代码上传到github

编写完代码后,我们需要把它上传到github上,之后在组件发布到npm的时候也需要用到代码的github地址
。如果你没有做github相关的配置,可以参考我另一篇文章:安装GIt并配置连接GitHub

执行以下命令把代码同步到你github对应的repository中:

$ git add .
$ git commit -a -m "initial commit"
$ git push -u origin master

同步之后可以到github中看下是否push成功:

https://github.com/YourGithubAccount/YourRepository

3.2 组件发布

开发好组件之后,想在其他的项目(或者提供给其他人安装使用)中通过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:

$ npm config get registry

切换

当然也可以通过命令切换当前使用的npm registry

# 全局切换
$ npm config set registry http://registry.npmjs.org/

有时候你可能只想在执行某些npm命令时临时切换,这个时候,可以使用--registry来指定临时切换的registry,比如在npm发布

$ npm publish --registry http://registry.npmjs.org/

就可以临时指定,当然,在命令执行结束之后,registry仍然会恢复到原来的registry

3.2.2 创建/登陆npm registry账户

要发布组件到npm registry,你必须要是npm registry的注册用户,通过:

$ npm adduser

来新增一个用户,或者你已经在官网注册了一个用户,可以通过:

$ npm login

来登陆npm registry账户。

利用以下两种方式来确认你是否创建/登陆成功npm registry

  1. 命令$ npm whoami确认本地是否成功登陆认证成功
  2. 在线打开 https://npmjs.com/~username 查看是否创建账户成功

3.2.3 发布前准备

3.2.3.1 .gitignore 和 .npmignore

  1. .gitignore中定义哪些文件不上传到github中
  2. .npmignore中定义哪些文件发布时不打包
  3. 如果有.gitignore但是没有.npmignore文件,那么.gitignore可以充当.npmignore的作用
  4. 具体规则可以参照:npm-developers, .gitignore or .npmignore pattern rules

3.2.3.2 package.json

package.json文件定义了发布的所有信息,包括:组件名、版本、作者、描述、依赖等等关键信息。具体可以参照 Working with package.json

下面是react-native-cardview的package.json文件内容:

{
"name": "react-native-rn-cardview",
"version": "1.0.0",
"description": "A ReactNative CardView Component for android and iOS",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"react-native",
"react-component",
"react-native-component",
"react",
"mobile",
"ios",
"android",
"cardview"
],
"author": {
"name": "quenice",
"email": "qiubing.it@gmail.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git@github.com:quenice/react-native-cardview.git"
},
"devDependencies": {
"react": "^16.2.0",
"react-native": "^0.53.0"
},
"peerDependencies": {
"react": "^16.2.0"
},
"dependencies": {
"prop-types": "^15.6.0"
}
}

3.2.3.3 编写readme.md

可以在readme.md文件中详细说明组件的使用方法、注意事项等。一般使用Markdown语法来编写

3.2.4 发布

做好以上准备之后,就可以发布了。这里需要注意,首次发布跟后面更新发布是不一样的。

首次发布

第一次发布的话,直接执行命令:

$ 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>的方式来自动更新版本号了

4 测试

组件从开发到最终发布的过程中,需要不断进行测试,确保功能正常,那如何进行测试呢?

4.1 创建一个react-native项目

首先我们创建一个叫做example的react-native项目

$ react-native init example

example项目目录可以和组件项目目录react-native-cardview同级,当然你也可以放在任何你想放的位置,这里为了操作方便,我们就把两个目录放在同级目录。也就是说,现在的目录是这样

$ tree
.
├── example
└── react-native-cardview

然后我们要做的就是把本地或者已发布的组件安装到example项目中进行测试

4.2 本地代码测试

在组件未发布之前,我们可以直接安装本地代码到example项目中进行测试,有以下几种方式都可以做到

4.2.1 yarn link

$ cd react-native-cardview
$ yarn link
$ cd ../example
$ yarn link react-native-cardview
$ react-native link react-native-cardview

说明几点:

  1. yarn link是把当前目录中的本地代码用yarn注册为react-native-cardview的一个本地组件,组件名字react-native-cardview其实是根据package.json中的name字段的值来的,跟目录名无关,只不过这里正好等于目录名
  2. yarn link react-native-cardview命令是把这个本地组件react-native-cardview安装到了example的项目中,你可以在example/node_modules中找到这个组件
  3. react-native link react-native-cardview这个大家应该知道,就是做了android/iOS的原生模块link
  4. 其实yarn link这种方式简单来说,就是做了一个symbol link,也就是说,example/node_modules/react-native-cardview/目录中的内容是指向react-native-cardview/目录内容,你改动react-native-cardview/目录下的代码,相当于直接改动example/node_modules/react-native-cardview/这个目录中的代码,这样就能够达到边修改组件代码边看效果的目的了

4.2.2 package.json中配置本地路径

直接在examplepackage.json中增加dependencies

example/package.json

{
"name":"example",
...
"dependencies": {
"react-native": "^0.55.4",
"react-native-cardview":"file:../react-native-cardview",
...
}
...
}

然后执行

$ react-native link react-native-cardview

yarn link一样,也相当于做了symbol link,直接修改react-native-cardview/目录下的代码,相当于直接改动example/node_modules/react-native-cardview/这个目录中的代码

4.2.3 直接copy本地代码

这种方式就比较简单粗暴了,直接copyreact-native-cardview/目录中内容到example/node_modules/react-native-cardview/这个目录中

$ cp -rf react-native-cardview/ example/node_modules/

然后执行

$ react-native link react-native-cardview

这种方式缺点就是每次在react-native-cardview/改完代码后,需要手工copy到example/node_modules/react-native-cardview/

4.3 已上传/发布代码测试

已上传到github或者发布到npm registry的组件,测试方式就跟普通我们安装一个第三方组件一样了。

4.3.1 通过github

加入你的代码通过git上传到了github仓库上,那么,你可以直接通过npm install来安装你的组件

npm install --save https://github.com/quenice/react-native-cardview.git

或者

npm install --save git@github.com:quenice/react-native-cardview.git

注意:根据你自己ghthub上的URL替换以上的HTTPS或者SSH

然后执行

$ react-native link react-native-rn-cardview

4.3.2 通过npm

这种方式就跟按照第三方组件没有区别了

$ npm install --save react-native-rn-cardview

然后执行

$ react-native link react-native-rn-cardview

结语

至此,一个react-native组件完整的开发-测试-发布的生命周期就讲完了。

由于是结合我自己开发的组件react-native-rn-cardview的实际开发过程,所以难免有遗漏,肯定也有许多不足的地方。如果大家有什么问题,或者发现哪里有错误,欢迎大家在评论区给我留言,我们一起探讨、一起解决。

另外如果在react-native中有需要用到CardView的,欢迎使用react-native-rn-cardview

开发自己的react-native组件并发布到npm[转]的更多相关文章

  1. Android React Native组件的生命周期及回调函数

    熟悉android的童鞋应该都清楚,android是有生命周期的,其很多组件也是有生命周期.今天小编和大家分享的React Native组件的生命周期,还不了解的童鞋,赶紧来围观吧 在android开 ...

  2. React Native v0.4 发布,用 React 编写移动应用

    React Native v0.4 发布,自从 React Native 开源以来,包括超过 12.5k stars,1000 commits,500 issues,380 pull requests ...

  3. beeshell —— 开源的 React Native 组件库

    介绍 beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 ...

  4. React Native组件(三)Text组件解析

    相关文章 React Native探索系列 React Native组件系列 前言 此前介绍了最基本的View组件,接下来就是最常用的Text组件,对于Text组件的一些常用属性,这篇文章会给出简单的 ...

  5. React Native组件(二)View组件解析

    相关文章 React Native探索系列 React Native组件系列 前言 了解了RN的组件的生命周期后,我们接着来学习RN的具体的组件.View组件是最基本的组件,也是首先要掌握的组件,这一 ...

  6. React Native组件的结构和生命周期

    React Native组件的结构和生命周期 一.组件的结构 1.导入引用 可以理解为C++编程中的头文件. 导入引用包括导入react native定义的组件.API,以及自定义的组件. 1.1 导 ...

  7. React Native组件间通信

    React Native组件间通信 React Native组件的关系有:父子关系.无直接关系.组件间通信主要针对这两类来讨论. 一.父组件和子组件之间通信 父组件向子组件传递消息.数据通过对子组件的 ...

  8. 如何创建一个前端 React 组件并发布到 NPM

    首先npm文档摆在这里: https://www.npmjs.cn/ 参考组件 https://github.com/rakuten-rex/rex-dropdownhttps://www.npmjs ...

  9. React Native组件之Text

    React Native组件之Text相当于iOS中的UILabel. 其基本属性如下: /** * Sample React Native App * https://github.com/face ...

随机推荐

  1. numba学习教程

    一.对于python的基础介绍 Python是一种高效的动态编程语言,广泛用于科学,工程和数据分析应用程序..影响python普及的因素有很多,包括干净,富有表现力的语法和标准数据结构,全面的“电池包 ...

  2. python11 函数的定义,调用,分类

    ## 复习 #一.什么是函数:具体特定功能的代码块 - 特定功能代码块作为一个整体,并给该整体命名,就是函数 # 二.函数的优点:# 1.减少代码的冗余# 2.结构清晰,可读性强# 3.具有复用性,开 ...

  3. python模拟蒙特·卡罗法计算圆周率

    蒙特·卡罗方法是一种通过概率来得到问题近似解的方法,在很多领域都有重要的应用,其中就包括圆周率近似值的计问题. 假设有一块边长为2的正方形木板,上面画一个单位圆,然后随意往木板上扔飞镖,落点坐标(x, ...

  4. Tomcat系列(7)——Tomcat类加载机制

    1. 核心部分 1. 类加载器: 通过一个类的全限定名来获取描述此类的二进制字节流. 对于任意一个类,都需要由加载他的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一 ...

  5. Nuxt.js笔记

    前置知识 SSR服务器渲染 Vue SSR(server side rendering)服务端渲染 和 Vue SPA(single page application)单页应用 Vue SSR-> ...

  6. Android AVD启动报错: This AVD's configuration is missing a kernel file! Please ensure the file "kernel-qemu" is in the same location as your system image.

    启动Android SDK manager重新下载安装

  7. IMDB-二分类问题

    from keras.datasets import imdb from keras.utils.np_utils import to_categorical import numpy as np f ...

  8. OSG开源教程(转)

    例:geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); 来指定要利用这些数据生成一个怎么样的形状. ...

  9. VGA、DVI、HDMI三种视频信号接口

    目前,电脑显示器常见的接口主要有HDMI.DP.DVI.VGA等4种接口.显示器数据线性能排名:DP>HDMI>DVI>VGA.其中 
VGA是模拟信号,已经被主流所淘汰,DVI.H ...

  10. Discuz x 转码要记

    Discuz 开源项目仅保留了 UTF8 编码版本,要从GBK版本升级,须进行编码转换. 转换主要执行以下步骤: 关闭网站,做好源文件备份: 导出数据库,在MySQL中生成Self-Contained ...