0%

CodePush

App的热更新即,不通过应用商店的审核,直接下载远程的代码更新用户手机中的app。由于iOS应用审核周期长,审核规则复杂所以热更新对于iOS平台来说显得更为迫切,但在原生的iOS代码中实现起来比较复杂,有被拒绝的风险。而React Native由于其加载jsbundle的特点,实现热更新并不复杂。而采用Js热更新的React Native并没有受到WaxPatch、JSPatch等热修复框架被禁止的影响。

React Native的热更新方案有很多种,比如微软的CodePush、或者如携程的jsbundle拆分方案等,但是基本原理都是一致的,就是远程加载jsbundle,下面记录实现热更新的几种方案

CodePush 是微软提供的一套用于热更新 React Native 和 Cordova 应用的服务。
CodePush 是提供给 React Native 和 Cordova 开发者直接部署移动应用更新给用户设备的云服务。CodePush 作为一个中央仓库,开发者可以推送更新 (JS, HTML, CSS and images),应用可以从客户端 SDK 里面查询更新。CodePush 可以让应用有更多的可确定性,也可以让你直接接触用户群。在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。

安装以及配置

安装code-push cli

在控制台输入

1
$ npm install -g code-push-cli

即可安装,完成之后输入code-push -v查看版本即代表安装成功

创建CodePush账号

在终端输入code-push register会打开注册的网页

注册成功之后会返回你一个token,复制粘贴到终端就完成了。

然后终端输入code-push login进行登录,登录成功后,你的session文件将会写在 /Users/你的用户名/.code-push.config

相关命令

  • code-push login 登陆
  • code-push loout 注销
  • code-push access-key ls 列出登陆的token
  • code-push access-key rm <accessKye> 删除某个 access-key

注册App

我们需要向CodePush注册我们的app,使用code-push app add <appname> <os> <platform>注册成功之后,会返回一套deployment key

1
2
$ code-push app add myapp-ios ios react-native
$ code-push app add myapp-android android react-native

ios应用和安卓应用建议分开创建

相关命令

  • add 在账号里面添加一个新的app
  • remove 或者 rm 在账号里移除一个app
  • rename 重命名一个存在app
  • list 或则 ls 列出账号下面的所有app
  • transfer 把app的所有权转移到另外一个账号

在项目中引用CodePush

在项目中添加CodePush插件

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

react-native版本在0.60以前需要执行

1
$ react-native link react-native-code-push

react-native版本在0.60以后需要执行

1
$ cd ios & pod install

iOS配置

  • info.plist

    修改info.plist 添加CodePushDeploymentKey键值对中的Staging的值,Deployment Key可以通过命令code-push deployment ls appName –displayKeys进行获取.也可以使用$(CODEPUSH_KEY)来自动适配Production或Staging环境, 如果填的是Production的key, 则打的包就是Production的包, 如果填的是Staging的key, 则打的包就是Staging的包.

  • 修改版本号

    将版本号修改为三位,如1.0.0

    如果你有很多的环境,那么多Scheme打包更加适合

    第一步,添加一个Scheme

    点击图中的➕号,选择Duplicate "Release" Configurations 即复制一个Release的配置,并修改成自己需要的名字,如Staging

    第二步,添加deployment key

    点击图中的➕号,选择Add User-Defined Setting 命名为CODEPUSH_KEY并将plist文件中的deployment key修改为$(CODEPUSH_KEY)

    第三步,如果需要在手机上部署多个环境的app,修改app显示的名字、以及app图标,则分别需要修改. Product NameAsset Catalog Compiler

    第四步,打包的时候,需要首先选中目标Scheme之后再执行打包命令

Android配置

  • 添加deployment Key

    可以直接在MainApplication.java中直接设置key,也可以写在build.gradle文件中

    在app/build.gradle文件中的buildTypes中添加一个新的打包环境

    并在strings.xml文件中添加一个CodePushDeploymentKey作为打包时候的code-push的key

  • 修改版本号

    将版本号修改为三位,如1.0.0

在Js代码中集成更新代码

一般来说更新的代码会放在App的入口文件里,每当用户进入App的时候就会检查是否存在更新。code-push提供了多种参数,可以控制热更新的更新时机、是否弹出框提示等。这里仅展示最简单的热更新参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import codePush from 'react-native-code-push' 

codePush.sync(
{
updateDialog: {
title: '发现新版本',
mandatoryUpdateMessage: '已有新版本可用',
mandatoryContinueButtonLabel: '立即更新',
optionalUpdateMessage: '已有新版本可用',
optionalIgnoreButtonLabel: '取消',
optionalInstallButtonLabel: '立即更新',
appendReleaseDescription: true,
descriptionPrefix: '\n\n更新内容:\n',
},
deploymentKey: Config.key,
installMode: codePush.InstallMode.IMMEDIATE
},
this.codePushStatusDidChange,
this.codePushDownloadDidProgress,
);

codePushStatusDidChange = async (syncStatus: any) => {
switch (syncStatus) {
case codePush.SyncStatus.CHECKING_FOR_UPDATE:
// 0 - 正在查询CodePush服务器以进行更新。
console.info('[CodePush] Checking for update.');
break;
case codePush.SyncStatus.AWAITING_USER_ACTION:
// 1 - 有可用的更新,并且向最终用户显示了一个确认对话框。(仅在updateDialog使用时适用)
console.info('[CodePush] Awaiting user action.');
break;
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
// 2 - 正在从CodePush服务器下载可用更新。
console.info('[CodePush] Downloading package.');
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
// 3 - 已下载一个可用的更新,并将其安装。
console.info('[CodePush] Installing update.');
break;
case codePush.SyncStatus.UP_TO_DATE:
// 4 - 应用程序已配置的部署完全最新。
console.info('[CodePush] App is up to date.');
break;
case codePush.SyncStatus.UPDATE_IGNORED:
// 5 该应用程序具有可选更新,最终用户选择忽略该更新。(仅在updateDialog使用时适用)
console.info('[CodePush] User cancelled the update.');
break;
case codePush.SyncStatus.UPDATE_INSTALLED:
// 6 - 安装了一个可用的更新,它将根据 SyncOptions 中的 InstallMode指定在 syncStatusChangedCallback 函数返回后立即或在下次应用恢复/重新启动时立即运行。
console.info('[CodePush] Installed update.');
break;
case codePush.SyncStatus.SYNC_IN_PROGRESS:
// 7 - 正在执行的 sync 操作
console.info('[CodePush] Sync already in progress.');
break;
case codePush.SyncStatus.UNKNOWN_ERROR:
// -1 - 同步操作遇到未知错误。
console.info('[CodePush] An unknown error occurred.');
break;
}
};

// code-push更新进度,可以配合页面添加下载进度条
codePushDownloadDidProgress = (progress: any) => {
const curPercent = progress.receivedBytes / progress.totalBytes;
};

使用CodePush进行热更新

首先将app打包好并安装在手机中

iOS打包首先要切换到目标Scheme后,再点击Archive

Android则需要先打出bundle包,之后再执行相应的打包命令

1
react-native bundle --platform android --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res/ --dev false

热更新

再次修改完js代码之后,执行以下命令即可将本次更新快速上传到服务器中

1
2
$ code-push release-react myapp-ios ios  --t 1.0.0 --dev false --d Staging --des "更新日志" --m true
$ code-push release-react myapp-android android --t 1.0.0 --dev false --d Staging --des "更新日志" --m true

–t代表本次热更新的app目标版本,即只有该版本下的app用户才能接收到本次热更新推送。如果一直没有更新原生代码,则不需要变动

–dev代表是否为开发模式

–d代表本次热更新的目标环境

–des代表着更新说明

–m代表是否强制更新

上传成功之后,再次打开app即可看到热更新的推送,app将会根据预先写好的更新策略进行更新

参考链接