版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/y4x5M0nivSrJaY3X92c/article/details/81976844

作者 | 钱凯

https://mmbiz.qpic.cn/mmbiz_jpg/ibm2sb53lRhyW3xoCtaqg02KEXCAMdfQBBVbQAkcc8U0KLCcAr998hrwbulN8ic7TzwrV2PpL31Dib8LySMe6hh1Q/640?wx_fmt=jpeg" alt="640?wx_fmt=jpeg" />

杏仁移动开发project师,前嵌入式project师。关注大前端技术新潮流。

本文使用的环境:

  • React@16.3.1

  • React Native@0.55.4

  • react-native-code-push@5.3.4

  • Android SDK@23

  • Android Build Tool@23.0.3

  • Gradle@2.14.1

  • Android Gradle Plugin@2.2.3

Why CodePush?

CodePush 是微软提供的一个热更新前后台方案。它对 React Native 项目有非常好的支持。

眼下针对 React Native 的 hot update 方案有很多。可是 CodePush 是最成熟稳定的方案,它最大的特点是提供了完整的后台工具。它基本的长处是:

  • 微软出品,大厂保证

  • 良好的多环境支持(Testing。Staging, Production)

  • 灰度公布、自己主动回滚等等特性

  • 良好的数据统计支持:下载、安装、出错一目了然

  • 强大的 CLI 工具,一个终端搞定所有流程

因为 React Native 运行的是脚本 js 文件,对热更新有天然的亲和,有余力的团队能够尝试实现自己的框架,一个简单的实现思路是:

  • 改动载入 jsBundle 的代码,转而从指定的本地存储位置去载入。假设没有。下载 bundle, 而且本次打开使用 app 包中的 bundle。

  • 假设找到 jsBundle 文件。调用 api 比較版本号号,假设不一致,则从指定server下载最新的 bundle 进行替换。

  • 通过反射调用私有方法。在下载完毕的回调中更新运行时资源。从而能马上看到更新的效果。

  • 使用相似 google-diff-match-patch 的 diff 工具。生成差异化补丁。不必下载完整 bundle,从而大大减小补丁包体积。

网上有非常多资料和源代码。这里就不细述了。

后台配置

为了使用 Code Push 公布热更新,我们须要向微软服务注冊我们的应用。

这部分工作微软提供了强大的命令行工具:CodePush CLI

wx_fmt=png" alt="640?

wx_fmt=png" />

安装 cli 工具

npm 全局安装:

npm install -g code-push-cli

关联账号

使用命令

code-push register

注冊一个账号,能够直接使用 GitHub 账号授权。完毕后将 token 复制回命令行中。

wx_fmt=png" />

使用 whoami 查看登录状态:

code-push whoami

注冊应用

登录成功后,我们注冊一个app:

code-push app add 你的App名称 android react-native

注意一定要为 Android 和 iOS 分别注冊,两者的更新包内容会有差异。

https://mmbiz.qpic.cn/mmbiz_png/ibm2sb53lRhzxaMSGDemUgg3KCXWR3Epv5YYLU1402029M3sz8rMcZZ0qj2tKGlsa5ia3g4Tcyqe5Eu96pS9LJLQ/640?wx_fmt=png" alt="640?

wx_fmt=png" />

查询状态

每一个 App 有不同的运行时环境。比方 Production,Staging等,我们也能够配置自己的环境。查看 App 的不同环境和部署状况:

code-push deployment ls 注冊的app名称

wx_fmt=png" alt="640?wx_fmt=png" />

眼下我们还没有公布不论什么更新。所以表中的状态是空的。

到这里就完毕了后端的基本配置。

App端配置

版本号兼容

安装 Code Push 环境前首先要 check 版本号的兼容性问题,不同的RN版本号须要使用不同的 Code Push。原则上我们建议将 RN 和 CodePush 都升级到最新版本号。

下表是官方文档中的兼容性说明:

React Native version(s) Supporting CodePush version(s)
<0.14 Unsupported
v0.14 v1.3 (introduced Android support)
v0.15-v0.18 v1.4-v1.6 (introduced iOS asset support)
v0.19-v0.28 v1.7-v1.17 (introduced Android asset support)
v0.29-v0.30 v1.13-v1.17 (RN refactored native hosting code)
v0.31-v0.33 v1.14.6-v1.17 (RN refactored native hosting code)
v0.34-v0.35 v1.15-v1.17 (RN refactored native hosting code)
v0.36-v0.39 v1.16-v1.17 (RN refactored resume handler)
v0.40-v0.42 v1.17 (RN refactored iOS header files)
v0.43-v0.44 v2.0+ (RN refactored uimanager dependencies)
v0.45 v3.0+ (RN refactored instance manager code)
v0.46 v4.0+ (RN refactored js bundle loader code)
v0.46-v0.53 v5.1+ (RN removed unused registration of JS modules)
v0.54-v0.55 v5.3+ (Android Gradle Plugin 3.x integration)

安装包

使用命令:

npm info react-native-code-push

来查看包相关信息。

我们建议始终将RN、React以及一些相关库升级到最新版本号。在根文件夹下使用命令:

npm install --save react-native-code-push

来安装最新版本号的 CodePush。

也能够參照上面的兼容性表格。安装指定版本号:

npm install --save react-native-code-push@5.1.4

project配置(Android)

假设project创建的时候比較早。可能是使用命令create-react-native-app来创建的,则须要在根文件夹运行:

npm run eject

来改变project结构。防止后面的兼容性问题。

配置安卓project,官方提供了两种途径:

  • 使用命令行工具rnpm(如今已经被整合到React Native CLI工具中了)。

    运行

react-native link react-native-code-push
  • 手动配置

假设你是新手,或者对 gradle、安卓project结构不了解,我们强烈建议运行一次手动配置,帮助理解究竟发生了什么。

手动配置

step 1

android/settings.gradle文件里加入:

include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')

这个文件定义了哪些 module 应该被加入到编译过程。对于单个 module 的项目能够不用须要这个文件,可是对于 multiModule 的项目我们就须要这个文件。否则 gradle 不知道要载入哪些项目。

这个文件的代码在初始化阶段就会被运行。

我们加入的内容告诉 gradle:去 node_modules 文件夹下的 react-native-code-push 载入 CodePush 子项目。

step 2

在 android/app/build.gradle 中的 dependencies 方法中加入依赖:

...
dependencies {
   ...
   compile project(':react-native-code-push')
}

这样就能在主project中引用到 CodePush 模块了。

step 3

继续在 android/app/build.gradle 中,加入在编译打包阶段 CodePush 须要运行的 task 引用:

...
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
...

这段代码事实上就是调用了 project 对象的 apply 方法,传入了一个以 from 为 key 的 map。完整写出来就是这种:

project.apply([from: '../../node_modules/react-native-code-push/android/codepush.gradle'])

apply from 和 apply plugin的差别在于,前者是从指定 url 去载入脚本文件。后者则用是从仓库拉取 plugin id 相应的二进制运行包。

step 4

CodePush 公布有各种环境(deployment)。默认有 Staging 和 Production,我们须要在 buildType 中配置相应的环境。而且设置 PushKey,从而让 App 端的 CodePush RunTime 依据不同的健值来下载正确的更新包。

查询各个环境 Key 的方法是使用上文安装的 CLI 工具:

code-push deployment ls App名称 -k

https://mmbiz.qpic.cn/mmbiz_png/ibm2sb53lRhzxaMSGDemUgg3KCXWR3EpvibUAL8Y0nYl91dqVSa2qibicTXy736HJH0I5XeOoicZyksrJWXlQOa1w2g/640?wx_fmt=png" alt="640?wx_fmt=png" />

上表中的 Deployment Key 就是相应环境的 Key 值了。

在 android/app/build.gradle 中。配置 buildTypes:

buildTypes {

    // 相应Production环境
   release {
       ...
       buildConfigField "String", "CODEPUSH_KEY", '"从上述结果中复制的production值"'
       ...
   }    // 相应Staging环境
   releaseStaging {
       // 从 release 拷贝配置,仅仅改动了 pushKey
       initWith release
       buildConfigField "String", "CODEPUSH_KEY", '"从上述结果中复制的stagingkey值"'
   }    debug {
       buildConfigField "String", "CODEPUSH_KEY", '""'
   }
}

注意这里不同 buildType 的命名,Staging 环境相应的 buildType 就叫releaseStaging,要符合这种命名规范。

Debug 环境尽管用不到 CodePush, 可是也要配置空的 Key 值,否则会报错。

step 5

处理完引用关系后,我们改动 MainApplication.java,在 App 运行时启动 CodePush 服务:

// 声明包
import com.microsoft.codepush.react.CodePush; public class MainApplication extends Application implements ReactApplication {    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
       ...
       // 重写 getJSBundleFile() 方法,让 CodePush 去获取正确的 jsBundle
       @Override
       protected String getJSBundleFile() {
           return CodePush.getJSBundleFile();
       }        @Override
       protected List<ReactPackage> getPackages() {
           return Arrays.<ReactPackage>asList(
               new MainReactPackage(),
               // 创建一个CodePush运行时实例
               new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG)
               ...
           );
       }
   };
}

js端引入 Code Push

配置完项目project后,我们将 CodePush 引入到 js 端。

首先将 App 的根组件包裹在 CodePush 中:

import codePush from "react-native-code-push";

AppRegistry.registerComponent('BDCRM', () => codePush(App));

CodePush 会在 App 启动后自己主动去 check 和更新最新的版本号。我们能够加入一些配置,让它在进入后台的时候也运行检查:

let codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };
AppRegistry.registerComponent('BDCRM', () => codePush(codePushOptions)(App));

CodePush js端的 api 不多,我们能够用这些 api 控制更新的一系列流程,经常使用的有:

// 检測是否有更新包可用
codePush.checkForUpdate(deploymentKey: String = null, handleBinaryVersionMismatchCallback: (update: RemotePackage) => void): Promise<RemotePackage>; // 获取本地最新更新包的属性
codePush.getCurrentPackage(): Promise<LocalPackage>; // 重新启动app(即使不用在 Hot Updating。也挺实用的)
codePush.restartApp(onlyIfUpdateIsPending: Boolean = false): void; // 手动进一次更新
codePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress), handleBinaryVersionMismatchCallback: function(update: RemotePackage)): Promise<Number>;

很多其它具体信息见文档。

使用 CodePush CLI 公布更新

完毕前后端的配置,打包公布应用后,兴许的改动我们就能通过 CLI 工具来公布啦!

升级前首先要 check:

  • 应用的版本号号要有更新(app/build.gradle: defaultConfig/versionName)

  • js bundle 要有改动,Code Push 会 diff 前后版本号。假设代码一致会觉得是无效的更新包

打开终端,进入到project文件夹,完整公布命令是:

code-push release-react <appName> <platform>
[--bundleName <bundleName>]
[--deploymentName <deploymentName>]
[--description <description>]
[--development <development>]
[--disabled <disabled>]
[--entryFile <entryFile>]
[--gradleFile <gradleFile>]
[--mandatory]
[--noDuplicateReleaseError]
[--outputDir <outputDir>]
[--plistFile <plistFile>]
[--plistFilePrefix <plistFilePrefix>]
[--sourcemapOutput <sourcemapOutput>]
[--targetBinaryVersion <targetBinaryVersion>]
[--rollout <rolloutPercentage>]
[--privateKeyPath <pathToPrivateKey>]
[--config <config>]

命令參数非常多,但用途都一目了然。嫌每次打麻烦的话,做成脚本也能够。

一般来说,我们公布应用首先会在測试环境进行稳定性測试。通过后再公布到生产环境中:

  • 打包公布 Staging 环境

code-push release-react 应用名 --platform android --deploymentName Staging --description "修复一些bug"

这样。我们 Staging 环境就能够收到更新推送啦。具体载入新 bundle 的实际。和我们在应用中配置的策略有关。上文已经介绍过了。

  • 測试 ok 后,提升(Promoting)到 Production 环境,而且进行灰度20%公布

code-push promote 应用名 Staging Production --rollout 20%
  • 在生产环境验证 ok,使用 patch 将灰度改动为100%,进行全网公布:

code-push patch 应用名 Production -rollout 100%

以上就是依照 測试 - 灰度 - 所有公布 步骤的一个典型 CodePush 公布工作流。

整体来说,CodePush 能满足我们灰度公布 React Native 应用的大部分需求了,由微软提供的server端支持能够节省非常多工作。是一个成熟可靠的方案。假设要说缺点,可能有几个须要考虑一下:

  • server速度。国内网络状况可能会影响下发的成功率和效率。

  • 污染代码,在 js 端必须将根节点包裹到 CodePush 模块中去,污染了代码。

  • 冗余,假设仅仅是想要简单的下发小体积的 js bundle。CodePush 显得太“重”,过于冗余了。这时候用轻量化的方案更好。

总之,我们依据自己项目的须要去进行选型就好了!

很多其它细节,能够參考文档

全文完


下面文章您可能也会感兴趣:

我们正在招聘 Java project师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

杏仁技术站

长按左側二维码关注我们。这里有一群热血青年期待着与您相会。

React Native 项目整合 CodePush 全然指南的更多相关文章

  1. Expo大作战(三)--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  2. 【腾讯Bugly干货分享】React Native项目实战总结

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 “8小时内拼工作,8小时外拼成长 ...

  3. React Native 项目运行在 Web 浏览器上面

    React Native 的出现,让前端工程师拥有了使用 JavaScript 编写原生 APP 的能力.相比之前的 Web app 来说,对于性能和用户体验提升了非常多. 但是 React Nati ...

  4. React Native 项目实战-Tamic

    layout: post title: React Native 项目实战 date: 2016-10-18 15:02:29 +0800 comments: true categories: Rea ...

  5. react native项目启动需要做的操作

    一.启动: 1.查看端口(默认8081是否被占用) netstat -ano   可以查看所有的进程 2.netstat -ano | findstr "8081"  查看某个端口 ...

  6. React Native项目集成iOS原生模块

    今天学习一下怎么在React Native项目中集成iOS原生模块,道理和在iOS原生项目中集成React Native模块类似.他们的界面跳转靠的都是iOS原生的UINavigationContro ...

  7. 安装android Studio和运行react native项目(基础篇)

    ANDROID_HOME环境变量 确保ANDROID_HOME环境变量正确地指向了你安装的Android SDK的路径. 打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设 ...

  8. 第一个React Native项目

    1>下图操作创建第一个React Native项目: 用Xcode运行界面如下: 记住: 在使用项目文件期间,终端记住不要关闭的哟!!! 改变了程序代码,需要刷新运行,使用快捷键: Comman ...

  9. React Native 项目常用第三方组件汇总

    React Native 项目常用第三方组件汇总 https://www.jianshu.com/p/d9cd9a868764?utm_campaign=maleskine&utm_conte ...

随机推荐

  1. 洛谷P1784 数独

    To 洛谷.1784 数独(类似(或者说相同)题:CODEVS.4966 简单数独(4*4数独) CODEVS.2924 数独挑战) 题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数 ...

  2. 喵哈哈村的魔法考试 Round #17 题解

    喵哈哈村的秘境探险系列. A. 实际上就是求乘积%k是否等于0,显然 a * b % k = (a%k)*(b%k)%k,所以边乘边取模就好了. #include<bits/stdc++.h&g ...

  3. 零基础学习hadoop到上手工作线路指导初级篇:hive及mapreduce(转)

    零基础学习hadoop到上手工作线路指导初级篇:hive及mapreduce:http://www.aboutyun.com/thread-7567-1-1.html mapreduce学习目录总结 ...

  4. react-native学习资源

    转载链接:  http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/react-native-learning-resources/ 这是 ...

  5. copy unicode HTML to clipboard

    How to copy unicode HTML code to the clipboard in html format, so it can be pasted into Writer, Word ...

  6. Linux 下安装 Mongodb

    mongodb在linux下面的安装应该是很简单的,但是有一个小点需要注意,这也就是我为什么写这篇博客的原因. 首先到其官网上下载最新稳定版,解压到目录,如/usr/local/mongodb 在mo ...

  7. Android Studio 3.1 正式版

    欢迎大家推荐自己在Android开发过程中用的好用的工具.学习开发教程.用到设计素材.如果你觉得本站对你有用,你可以点击底部的分享按钮,把本站分享到社交网络让你的小伙伴和更多的人知道. 或者可以考虑捐 ...

  8. 未能找到temp\select2.cur的一部分

    环境 操作系统:win10 家庭普通版本 x64 账户类型:管理员 SuperMap:9D 打开自定义的应用程序时,会报错:未能找到路径"C:\Users\user\AppData\Loca ...

  9. Spark机器学习(12):神经网络算法

    1. 神经网络基础知识 1.1 神经元 神经网络(Neural Net)是由大量的处理单元相互连接形成的网络.神经元是神经网络的最小单元,神经网络由若干个神经元组成.一个神经元的结构如下: 上面的神经 ...

  10. [Done]SnowFlake生成Long类型主键返回前台过长导致精度缺失的问题

    问题描述: 在开发过程中,项目的主键生成器是SnowFlake,其生成的long主键是28位, 但是js中Long的最大值:https://blog.csdn.net/sunmerZeal/artic ...