npm 发布一个react-native组件react-nati

作者: 星辰大海_王 | 来源:发表于2019-03-19 13:54 被阅读9次

    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

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

    注意:初次注册、登录npm账号,需要填写邮箱,并进行激活

    3.2.3 发布前准备(编写git、npm等配置文件)

    编写.gitignore 和 .npmignore文件
    1. .gitignore中定义哪些文件不上传到github中
    2. .npmignore中定义哪些文件发布时不打包
    3. 如果有.gitignore但是没有.npmignore文件,那么.gitignore可以充当.npmignore的作用
    4. 具体规则可以参照: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

    相关文章

      网友评论

        本文标题:npm 发布一个react-native组件react-nati

        本文链接:https://www.haomeiwen.com/subject/xxvvmqtx.html