原文地址:http://blog.csdn.net/lovelyelfpop/article/details/50848524javascript
插件地址:https://github.com/nordnet/cordova-hot-code-pushcss
如下是我对GitHub项目readme的翻译
html
——————————————————————————————————————————————java
Cordova Hot Code Push Pluginandroid
此插件提供了可以使cordova app本身主动更新web内容的功能。ios
基本上, 你App中所有位于 www
文件夹内的文件都可以被本身主动更新.git
当你又一次公布新的app时-又一次打包了web内容: html 文件, JavaScript 代码, 图片等等. 通常有两种方式进行升级:github
在appstore中上架新的app. 但是耗时比較长. web
牺牲所有原生功能。每次打开都从远端站点载入. 但是假设没有网络,app就无法使用. apache
此插件就为了解决问题而生. 当用户初次打开app - 它会将所有web内容复制一份到外部存储. 此后从外部存储载入web内容,而并不载入打包在app内部的web内容. app每次启动都会链接server检查更新并下载新的web内容. 假设下载了更新 - 这次更新内容将会在下次app启动时生效.
这样, 你的app就获得了实时更新, 并且也能在离线的时候使用. 还有,插件赞成你对web内容设置最小支持的app外壳版本号, 以保证新的web内容可以在旧的app外壳上执行.
App Store可以上架这样的app吗? 可以... 仅仅要你更新后的web内容符合app一開始的功能. 假设原本是个计算器, 更新后变成了一个音乐播放器 - 这是会被禁止的.
Android 4.0.0 或以上.
iOS 7.0 或以上.
需要cordova 5.0+
cordova plugin add cordova-hot-code-push-plugin
也可直接从 仓库url 安装(不稳定)
cordova plugin add https://github.com/nordnet/cordova-hot-code-push.git
插件安装完后,会推荐你安装Cordova Hot Code Push 命令行client. 此客户的可以帮助你:
方便生成必须的app配置文件;
启动本地server,监听开发模式下的web内容变动,并直接部署新版本号.
固然,你也可以不用这个命令行client, 仅仅是用了它会更加方便.
在版本号 1.0.x 的时候,本地开发模式集成到了此插件里面. 从 v1.1.x 開始这部分功能做为了此插件的一个扩展,移到了这里. 因为 v1.0 版本号为了支持ios的Swift作了一些优化 - 升级到 v1.1.x 你需要禁用它.
又一次安装 iOS platform的办法:
cordova platform remove ios cordova platform add ios
当 platform 被加入以后 - 所有插件会本身主动安装.
进阶 - 手动移除 Swift 支持. 你需要用Xcode打开 iOS 项目, 而后:
在 Build Settings
,设置 Embedded Content Contains Swift Code
为 NO
.
打开 <YOUR_PROJECT_NAME>-Prefix.pch
, 移除 #import <YOUR_PROJECT_NAME>-Swift.h
. 比方:
#ifdef __OBJC__ #import "TestProject-Swift.h" #endif
又一次build, 检查是否正常.
此向导展现了在开发中怎样高速使用这个插件. 咱们需要加入 开发扩展 。需要 Xcode 7, 虽然hot code push plugin插件自身可以支持低版本号xcode.
建立新的Cordova项目。并加入android和iOS platform:
cordova create TestProject com.example.testproject TestProjectcd ./TestProject cordova platform add android cordova platform add ios
或者可以用一个已有的项目.
加入插件:
cordova plugin add cordova-hot-code-push-plugin
加入开发扩展:
cordova plugin add cordova-hot-code-push-local-dev-addon
安装 Cordova Hot Code Push 命令行client:
npm install -g cordova-hot-code-push-cli
启动本地server:
cordova-hcp server
你会看到如下的命令行输出:
Running server Checking: /Cordova/TestProject/www local_url http://localhost:31284 Warning: .chcpignore does not exist. Build 2015.09.02-10.17.48 created in /Cordova/TestProject/www cordova-hcp local server available at: http://localhost:31284 cordova-hcp public server available at: https://5027caf9.ngrok.com
打开新的控制台, 进入到项目根文件夹,执行app:
cordova run
稍等,app会安装到手机或者模拟器.
现在打开 TestProject/www/index.html
, 作一些修改而后保存. 几秒种后你可以在手机或模拟器上看到更新后的页面.
到此,你可以本地开发。新的web内容会本身主动在设备上更新,而无需又一次启动app查看效果.
此向导展现了在开发中怎样高速使用这个插件. 咱们需要加入 开发扩展 。需要 Xcode 7, 虽然hot code push plugin插件自身可以支持低版本号xcode.
建立新的Ionic项目,并加入android和iOS platform::
ionic start TestProject blankcd ./TestProject ionic platform add android ionic platform add ios
Or use the existing one.
加入插件:
ionic plugin add cordova-hot-code-push-plugin
加入开发扩展:
ionic plugin add cordova-hot-code-push-local-dev-addon
安装 Cordova Hot Code Push 命令行client:
npm install -g cordova-hot-code-push-cli
启动本地server:
cordova-hcp server
你会看到如下的命令行输出:
Running server Checking: /Cordova/TestProject/www local_url http://localhost:31284 Warning: .chcpignore does not exist. Build 2015.09.02-10.17.48 created in /Cordova/TestProject/www cordova-hcp local server available at: http://localhost:31284 cordova-hcp public server available at: https://5027caf9.ngrok.com
打开新的控制台, 进入到项目根文件夹。执行app:
ionic run
稍等。app会安装到手机或者模拟器.
现在打开 TestProject/www/index.html
, 作一些修改而后保存. 几秒种后你可以在手机或模拟器上看到更新后的页面.
到此,你可以本地开发,新的web内容会本身主动在设备上更新。而无需又一次启动app查看效果.
先防止所有的配置相关的内容弄得你稀里糊涂 - 先来看看此插件的实现更新功能的流程图. 应该没有技术细节.
用户打开你的app.
插件初始化,在后台进程启动 升级载入器(update loader).
Update loader 从 config.xml
取 config-file
配置(一个url),并今后url载入一段 JSON 配置. 而后它把这段JSON配置中的 release
版本 和当前app 已经安装的进行比較. 假设不一样 - 进入下一步.
Update loader 使用app配置(application config)中的 content_url
。去载入清单文件(manifest). 它会找出自上次升级以来,哪些文件需要更新.
Update loader 从 content_url
下载更新文件.
假设一切顺利 - 发出一个"升级文件已经准备好,可以安装了"的通知.
升级文件已安装, app又一次进入更新过的页面.
固然, 还有其它的细节, 只是你已经有了大体的思路.
每一个Cordova 项目都有一个 www
文件夹, 这里存放所有的web内容. 当cordova build
运行后 - www
里的内容会复制到相应platform的 www
文件夹下:
安卓: platforms/android/assets/www
.
iOS: platforms/ios/www
.
因而这些文件被打包进了app. 咱们不能更新安装包里的这些文件, 因为它们是仅仅读的. 正因为如此,因此咱们要在app第一次启动的时候,将内置的web内容(www文件夹)拷贝到外部存储. 咱们不想在拷贝过程当中堵塞ui - 咱们仍是会先载入app内置的index.html. 但是下一次启动或更新 - 咱们就从外部存储载入index.html.
但是假设你的app外壳须要添加新的cordova插件或者原生功能 - 你必须要又一次上架外壳app到store商店. 还有 - 添加外壳 app 的build版本 (App Store 或 Google Play强制的).下次启动,插件检查外壳app版本是否变化, 假设变了 - 会又一次拷贝内置web内容(www文件夹)到外部存储.
开发app的时候 - 你可能会困惑: 改了一些文件, 又一次启动了app - 但却看到的是旧的页面. 现在你知道缘由了: 插件用的是旧版本号的web内容(外部存储中). 若要清除缓存,你需要:
卸载app, 运行 cordova run
.
添加外壳app版本,强制插件又一次安装 www
文件夹. 更改外壳app版本请设置 config.xml文件的
android-versionCode
和 ios-CFBundleVersion
.
安装 本地开发扩展 ,让它帮你处理版本问题. 每次build他会本身主动帮你app的build版本加1,不需要你手动更改
上面就是简要介绍, 以便你理解大体的思路. 现在咱们继续深刻.
以后你会阅读到 配置文件 这一节- 这有app配置 (application config), 名字是chcp.json
. 里面有个 release
设置, 这个指明了web内容的版本号. 这个配置必须而且每次公布的release版本号必须不同. 它由 命令行client 本身主动生成。格式是: yyyy.MM.dd-HH.mm.ss
(比方 2015.09.01-13.30.35
).
每次公布,插件在外部存储本身主动生成一个以这个 release版本号 为名字的文件夹, 而后把web内容全部放到这里面. release版本号号成为了 url的一部分. 这个手段可以解决一些问题:
网页内容缓存问题. 比方, iOS 上。css 文件会被 UIWebView缓存起来, 即便咱们又一次加载了index.html - 新的样式仍是不会被应用. 你需要用任务管理器杀死app, 或者改变css的路径.
基本不会发生更新后损坏已有web内容的现象, 因为咱们每次更新都在不一样的文件夹下.
即便更新致使了web内容损坏 - 咱们可以回滚到上一个版本号的release.
比方, 咱们当前执行的release版本号是 2015.12.01-12.01.33
. 这意味着:
所有web内容存储在 /sdcard/some_path/2015.12.01-12.01.33/www/
. 包括了Cordova的资源.
Index 页面, 用户看到的是 /sdcard/some_path/2015.12.01-12.01.33/www/index.html
.
某个时候咱们公布了一个新的release: 2016.01.03-10.45.01
. 第一步,插件需要下载新的web文件, 发生状况例如如下:
在外部存储建立了一个以新的 release 版本为名字的文件夹: /sdcard/some_path/2016.01.03-10.45.01/
.
文件夹里面 - 又建立了一个 update
文件夹 : /sdcard/some_path/2016.01.03-10.45.01/update/
.
所有依据 chcp.manifest
更新的文件 都被下载到了这个 update
文件夹内.
新的 chcp.manifest
和 chcp.json
也被放到了 update
文件夹内.
新的web内容已准备安装.
安装更新的时候:
插件从当前正在使用的release版本号 文件夹内拷贝 www
下所有内容到 新的 release 版本号文件夹下. 用咱们的样例就是:从 /sdcard/some_path/2015.12.01-12.01.33/www/
拷贝所有文件到 /sdcard/some_path/2016.01.03-10.45.01/www/
.
从update
文件夹下拷贝新的web内容和配置文件,到 www
文件夹下: /sdcard/some_path/2016.01.03-10.45.01/update/
-> /sdcard/some_path/2016.01.03-10.45.01/www/
.
移除 /sdcard/some_path/2016.01.03-10.45.01/update/
文件夹。因为咱们再也不使用了.
载入新的release版本号index.html: /sdcard/some_path/2016.01.03-10.45.01/www/index.html
.
至此。插件会重新的release载入页面, 而旧的release则会做为一个备份留下来,以防万一.
Cordova Hot Code Push 命令行client 是一个命令行工具,以便你web内容的开发.
它可以:
生成 chcp.json
和 chcp.manifest
文件, 这样你就不用手动去建立;
执行本地服务,开发时可以检測更新,并公布新的release版本号,使得可以再设备上实时更新web内容;
部署你的web内容到外部server上.
固然, 你可以不使用这个命令行工具. 仅仅是用了它会更方便一些.
当你本地开发app时 - 通常作法相似:
web项目作一些更改.
运行 cordova run
启动app.
稍等一会查看执行结果.
即便很是小的变动也需要打包重装app. 耗时比較久,比較麻烦.
为了提高速度 - 你可以使用本地开发扩展 Hot Code Push Local Development Add-on. 安装很是简答:
加入此cordova插件.
启动本地服务 cordova-hcp server
.
在你的项目的config.xml
文件里 <chcp />
块下加入 <local-development enabled="true" />
.
启动app.
这样, 所有web内容的变动都会被插件检測到, 并直接更新显示到app上,而不需要从新启动app.
仅仅有在加入了新的cordova插件时你才会从新启动app.
重要: 你应该仅仅在开发状态下使用此扩展. 公布外壳app的时候,应该移除此扩展: cordova plugin remove cordova-hot-code-push-local-dev-addon
.
你应该知道, Cordova 使用 config.xml
文件配置不一样项目: app名字, 描写叙述, 起始页面,等等. 使用config.xml文件。你也可以为此插件配置.
这些配置位于 <chcp>
块. 比方:
<chcp> <config-file url="https://5027caf9.ngrok.com/chcp.json"/> </chcp>
定义了一个 URL。指定了需要从哪里载入app配置(application config,就是chcp.json). URL 在 url
属性中声明. 此项必须.
以防万一,开发的时候, 假设 config-file
未定义 - 会本身主动设为本地服务上 chcp.json 的路径.
本身主动下载web内容更新. 默认是本身主动, 假设你想手动下载web内容更新,你可以使用 JavaScript 模块(如下有).
禁用本身主动下载可以设置 config.xml
:
<chcp> <auto-download enabled="false" /> </chcp>
默认是 true
.
本身主动安装. web内容更新. 默认是本身主动, 假设你想手动安装web内容更新,你可以使用 JavaScript 模块(如下有).
禁用本身主动安装可以设置 config.xml
:
<chcp> <auto-install enabled="false" /> </chcp>
默认是 true
.
此插件用到2个配置文件:
app配置 Application config - 包括最新的release信息: release 版本, 最低需要的外壳app版本,等等. 文件名称 chcp.json
Web内容清单 Content manifest - 包括所有web内容文件的名字和MD5值. 文件名称 chcp.manifest
这两个文件必须. 他们描写叙述了是否有新的release版本号,以及文件更新时的比較.
另外一个build 可选參数 (build options) 文件, 可以再运行cordova build
命令时指定插件的配置.
包括最新版本号的release信息.
简单的样例:
{ "content_url": "https://5027caf9.ngrok.com", "release": "2015.09.01-13.30.35"}
这个文件应该放在 www
文件夹下,文件名称是 chcp.json
. 这个文件也被打包到了外壳app内.
你可以手动建立它, 或者用 cordova-hcp
命令(Cordova Hot Code Push 命令行)本身主动生成. 仅仅要在cordova项目根文件夹下执行 cordova-hcp init
, 之后要公布新的release仅仅要执行 cordova-hcp build
. 不少其它内容请阅读 命令行client的文档.
服务端URL, 也就是你所有web内容文件的位置. 插件会把它做为下载新的清单文件、新的web内容文件的 base url. 此项必须.
不论什么字符串. 每次release应该惟一. 插件基于这个才知道有没有新版本号release. 此项必须.
重要: 插件仅仅比較release字符串是否相等, 假设不等,就以为服务端有新版本号.(不会比較大小)
所需最小的外壳app版本号. 这是app的build版本号号。是个整型数字, 不是应用商店中看到的形如"1.0.0"字符串.
在 config.xml
中。这样指定build版本:
<widget id="io.cordova.hellocordova" version="1.0.1" android-versionCode="7" ios-CFBundleVersion="3">
version
- app字符串版本号号, 也就是用户在商店中看到的版本号.
android-versionCode
- 安卓的build版本. 这个应该用于 min_native_interface
.
ios-CFBundleVersion
- iOS的build版本.这个应该用于 min_native_interface
.
Preference creates dependency between the web and the native versions of the application.
重要: 因为cordova的一个奇葩现象, 生成的 .apk
的build版本会被加 10, 致使了变成了形如 70, 72, or 74, 依据不一样平台 (arm/x86/etc),后面的0、二、4不同. 为了绕过这个, 咱们建议也给 iOS build版本手动加10, 这样 min_native_interface
(比方 70
) 就可以对安卓和iOS都有效, 大体是这样:
<widget id="io.cordova.hellocordova" version="1.0.1" android-versionCode="7" ios-CFBundleVersion="70">
举个样例, 若是你的外壳app加了个新的插件 - 你应该会更新外壳app. 为了防止用户下载了不适合他现有外壳app的web内容 - 你应该设置 min_native_interface
这个值.
比方, 咱们app里的chcp.json是这种:
{ "content_url": "https://5027caf9.ngrok.com", "release": "2015.09.01-13.30.35", "min_native_interface": 10}
外壳app的build版本号是 13
.
某个时候,web内容有了新的release公布:
{ "content_url": "https://5027caf9.ngrok.com", "release": "2015.09.05-12.20.15", "min_native_interface": 15}
插件载入到这段json的时候, 发现 min_native_interface
比当前外壳app的build号要大 - 它就不会下载web内容. 而是触发一个 chcp_updateLoadFailed
错误通知, 告诉用户需要升级外壳app了. 不少其它内容请看 从应用商店请求app升级 小节.
备注: 眼下你还不能为不一样平台指定不一样的 min_native_interface
. 假设需要之后可以支持.
指定了何时安装web内容更新. 支持的值有:
start
- app启动时安装更新. 默认值.
resume
- app从后台切换过来的时候安装更新.
now
- web内容完成下载即安装更新.
你可以用JavaScript禁止本身主动安装. 请看 JavaScript module 小节.
apk包名. 假设指定了 - 引导用户到 Google Play Store 的app页面.
ios应用标识号, 比方: id345038631
. 假设指定了 - 引导用户到 App Store 的app页面.
内容清单描写叙述了web项目所有文件的状态.
[ { "file": "index.html", "hash": "5540bd44cbcb967efef932bc8381f886" }, { "file": "css/index.css", "hash": "e46d9a1c456a9c913ca10f3c16d50000" }, { "file": "img/logo.png", "hash": "7e34c95ac701f8cd9f793586b9df2156" }, { "file": "js/index.js", "hash": "0ba83df8459288fd1fa1576465163ff5" } ]
依据它,插件才知道什么文件被移除了, 什么文件更新或新增了. 因而:
更新阶段。从服务端下载所有web内容文件;
安装阶段,删除服务端不存在(已移除)的文件.
这个文件应该放在 www
文件夹下,文件名称是 chcp.manifest
.这个文件也被打包到了外壳app内.
相同的, 清单文件要放到 content_url
(app配置 Application config中指定的)指定的文件夹下. 比方, 假设你的 content_url
是 https://somedomain.com/www
, 这个清单文件的url就必须是 https://somedomain.com/www/chcp.manifest
.
生成 chcp.manifest
文件可以运行命令行client的 build
命令 (在cordova项目根文件夹下运行):
cordova-hcp build
相对于 www
的路径(就是你存放web内容的地方).
比方, 你的web内容位于: /Workspace/Cordova/TestProject/www.
你的 file
值应该是相对于这个路径.
文件的 MD5 值. 用于检測自上次release以来。这个文件是否变动过. 还实用于检測app端下载的文件是否出错.
建议: 每次变动web内容后都应该更新 chcp.manifest
文件. 不然插件不会检測到不论什么更新.
就像在 Cordova 配置项 一节中说的 - 你可以在config.xml
文件中改变插件配置.
但是假设你想在使用build命令行的时候改变插件配置呢? 为了达到这个目的,你需要使用chcpbuild.options
文件.
文件必须位于 Cordova 项目根文件夹. 在这个文件中面。你指定(JSON格式) 所有你想改变 config.xml
文件的配置. 源文件 config.xml
(Cordova项目根文件夹) 不会发生变更, 咱们改变的是 特定平台下的 config.xml
(在cordova build过程的 after_prepare
阶段).
比方, 你的Cordova项目是 /Cordova/TestProject
文件夹.config.xml
文件 (/Cordova/TestProject/config.xml
) 有如下的配置:
<chcp> <config-file url="https://company_server.com/mobile/www/chcp.json" /> </chcp>
这时咱们在 /Cordova/Testproject/
下建立 chcpbuild.options
文件,文件内容例如如下:
{ "dev": { "config-file": "https://dev.company_server.com/mobile/www/chcp.json" }, "production": { "config-file": "https://company_server.com/mobile/www/chcp.json" }, "QA": { "config-file": "https://test.company_server.com/mobile/www/chcp.json" } }
build app的时候, 转为开发要用的server, 可运行:
cordova build -- chcp-dev
结果就是, 特定拍下的 config.xml
文件(比方, /Cordova/TestProject/platforms/android/res/xml/config.xml
) 变成了这样:
<chcp> <config-file url="https://dev.company_server.com/mobile/www/chcp.json"/> </chcp>
你可能注意到了 - 咱们用的命令有个 chcp-
. 这个必须, 这样插件才知道, 这个參数是为它设置的. 而且, 不会和其余插件的命令參数冲突.
假设你的app可以測试了 - 你可以用如下的命令build, 就指定了測试server:
cordova build -- chcp-QA
特定平台下的 config.xml
就会变成:
<chcp> <config-file url="https://test.company_server.com/mobile/www/chcp.json"/> </chcp>
当咱们需要上架app的时候 (Google Play, App Store) - 咱们正常build:
cordova build --release
这样 config.xml
是不会改变的.
假设没有使用 chcpbuild.options
- 插件会使用 config.xml
里面默认的值.
默认状况下, 所有的 检查更新->下载->安装 过程都是插件在原生端本身主动进行的. 不需要其余js端代码. 然而, 这些过程也可以用js控制.
你可以:
监听更新相关的事件;
从服务端检查和下载新的web内容;
安装已下载的web内容;
更改插件配置;
让用户到应用商店下载新的外壳app.
比方, web内容已经下载并可以安装了。会有事件通知, 或者出错了致使安装新的web内容失败了.
监听事件像这样:
document.addEventListener(eventName, eventCallback, false); function eventCallback(eventData) { // do something }
错误事件有具体错误信息. 像这样:
function eventCallback(eventData) { var error = eventData.details.error; if (error) { console.log('Error with code: ' + error.code); console.log('Description: ' + error.description); } }
可用的事件例如如下:
chcp_updateIsReadyToInstall
- web内容已经下载并可以安装时触发.
chcp_updateLoadFailed
- 插件没法下载web更新时触发. 具体错误信息在事件參数里.
chcp_nothingToUpdate
- 无可用更新下载时触发.
chcp_updateInstalled
- web内容成功安装时触发.
chcp_updateInstallFailed
- web内容安装失败时触发. 具体错误信息在事件參数里.
chcp_nothingToInstall
-无可用更新安装时触发.
chcp_assetsInstalledOnExternalStorage
- 插件成功把app内置的web内容复制到外置存储中时触发. 你可能需要开发调试时用到这个事件。或许不会.
chcp_assetsInstallationError
-插件没法拷贝app内置的web内容到外置存储中时触发. 假设此事件发生了 - 插件再也不工做. 或许是设备没有足够的存储空间致使. 具体错误信息在事件參数里.
该举一些简单的样例了. 若是咱们有个 index.js
文件, 它被 index.html
引用.
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, // deviceready Event Handler onDeviceReady: function() { console.log('Device is ready for work'); } }; app.initialize();
这个和cordova默认建立的 index.js
文件很是像. 监听 chcp_updateIsReadyToInstall
事件例如如下:
bindEvents: function() { // ...some other events subscription code... document.addEventListener('chcp_updateIsReadyToInstall', this.onUpdateReady, false); },
编写事件处理函数:
// chcp_updateIsReadyToInstall Event Handler onUpdateReady: function() { console.log('Update is ready for installation'); }
index.js
结果例如如下:
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); document.addEventListener('chcp_updateIsReadyToInstall', this.onUpdateReady, false); }, // deviceready Event Handler onDeviceReady: function() { console.log('Device is ready for work'); }, // chcp_updateIsReadyToInstall Event Handler onUpdateReady: function() { console.log('Update is ready for installation'); } }; app.initialize();
这样咱们就知道了web内容何时完成下载并可以安装了. 经过 JavaScript 模块咱们可以让插件即时安装web更新, 不然将在下次启动app时安装.
使用js代码。让插件检查更新:
chcp.fetchUpdate(updateCallback); function updateCallback(error, data) { // do some work }
回调有2个參数:
error
- 假设检查失败,有error參数; null
表示一切正常;
data
- 额外的 数据, 原生端提供. 临时可以忽略.
咱们若是 index.html
有一些button, 按下它可以检查更新. 咱们需要这样写代码:
监听button的 click
事件.
当点击button时调用chcp.fetchUpdate()
.
处理更新事件的结果.
咱们来改 index.js
代码:
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, // deviceready Event Handler onDeviceReady: function() { // Add click event listener for our update button. // We do this here, because at this point Cordova modules are initialized. // Before that chcp is undefined. document.getElementById('myFetchBtn').addEventListener('click', app.checkForUpdate); }, checkForUpdate: function() { chcp.fetchUpdate(this.fetchUpdateCallback); }, fetchUpdateCallback: function(error, data) { if (error) { console.log('Failed to load the update with error code: ' + error.code); console.log(error.description); } else { console.log('Update is loaded'); } } }; app.initialize();
注意: 即便你在fetchUpdate
回调里处理了,相关的更新事件仍是会触发并广播的.
调用:
chcp.installUpdate(installationCallback); function installationCallback(error) { // do some work }
假设安装失败 - error
參数会有错误具体信息. 不然- 为 null
.
现在让咱们来继续上面的代码,处理web内容下载完后的安装.
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, // deviceready Event Handler onDeviceReady: function() { // Add click event listener for our update button. // We do this here, because at this point Cordova modules are initialized. // Before that chcp is undefined. document.getElementById('myFetchBtn').addEventListener('click', app.checkForUpdate); }, checkForUpdate: function() { chcp.fetchUpdate(this.fetchUpdateCallback); }, fetchUpdateCallback: function(error, data) { if (error) { console.log('Failed to load the update with error code: ' + error.code); console.log(error.description); return; } console.log('Update is loaded, running the installation'); chcp.installUpdate(this.installationCallback); }, installationCallback: function(error) { if (error) { console.log('Failed to install the update with error code: ' + error.code); console.log(error.description); } else { console.log('Update installed!'); } } }; app.initialize();
注意: 即便你在
installUpdate
回调里处理了,相关的更新事件仍是会触发并广播的
正常状况下,所有的插件配置都在 config.xml
. 但是你可以用js动态改变.
经过如下的代码实现:
chcp.configure(options, callback); function callback(error) { // do some work }
支持的有:
config-file
- application config(chcp.json) 的url. 假设设置了 - 这个url将会被用于检查更新,而不是config.xml
中的值.
auto-download
- 设为 false
你可以禁止插件本身主动检測web内容更新并下载.
auto-install
- 设为 false
你可以禁止插件本身主动安装web更新.
这些需要在 deviceready
事件中设置. 你应该在每个页面载入的时候处理,
假如你一开就打算手动更新和下载安装 - 你应该在config.xml中设置
<chcp> <auto-download enabled="false" /> <auto-install enabled="false" /> </chcp>
而不是js端动态设置.
比方, 咱们在config.xml禁用了 auto-download
and auto-install
. 而后某个时间点 config-file
改变了, 但是咱们不想从原有的url检測和下载web更新. 此时, 咱们应该这样:
公布新版本号的web内容, 它们可以用于最初的 config-file
url.
在新的版本号 index.js
文件里,内容像这样:
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, // deviceready Event Handler onDeviceReady: function() { // change plugin options app.configurePlugin(); }, configurePlugin: function() { var options = { 'config-file': 'https://mynewdomain.com/some/path/mobile/chcp.json' }; chcp.configure(options, configureCallback); }, configureCallback: function(error) { if (error) { console.log('Error during the configuration process'); console.log(error.description); } else { console.log('Plugin configured successfully'); app.checkForUpdate(); } }, checkForUpdate: function() { chcp.fetchUpdate(this.fetchUpdateCallback); }, fetchUpdateCallback: function(error, data) { if (error) { console.log('Failed to load the update with error code: ' + error.code); console.log(error.description); return; } console.log('Update is loaded, running the installation'); chcp.installUpdate(this.installationCallback); }, installationCallback: function(error) { if (error) { console.log('Failed to install the update with error code: ' + error.code); console.log(error.description); } else { console.log('Update installed!'); } } }; app.initialize();
从 Application config app配置 小节咱们知道。可以给web更新设置最小支持的外壳app版本号 (min_native_interface
). 假设插件检查发现用户安装的外壳app版本号比服务端新的web内容要求的版本号要低 - 就会触发错误事件。错误码chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW
. 经过这个错误码咱们可以引导用户去应用商店更新外壳app (Google Play /App Store).
这里你想怎么作就怎么作. 常常用法是显示一个对话框,问用户是否需要转到应用商店. 插件也提供了这个.
你需要作的是:
在 application config(chcp.json) 中设置t android_identifier
和 ios_identifier
.
js端监听对应事件,并在出现错误的时候调用 chcp.requestApplicationUpdate
方法.
举个样例. 简单起见咱们监听 chcp_updateLoadFailed
事件.
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, // Bind any events that are required. // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); document.addEventListener('chcp_updateLoadFailed', this.onUpdateLoadError, false); }, // deviceready Event Handler onDeviceReady: function() { }, onUpdateLoadError: function(eventData) { var error = eventData.detail.error; if (error && error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW) { console.log('Native side update required'); var dialogMessage = 'New version of the application is available on the store. Please, update.'; chcp.requestApplicationUpdate(dialogMessage, this.userWentToStoreCallback, this.userDeclinedRedirectCallback); } }, userWentToStoreCallback: function() { // user went to the store from the dialog }, userDeclinedRedirectCallback: function() { // User didn't want to leave the app. // Maybe he will update later. } }; app.initialize();
下载安装web更新的过程当中可能会发生一些错误. 你可以从回调或者事件中匹配错误码( chcp.error
对象中有各类错误码).
v1.2.0版本号以前 你需要用特定的错误码数字值. 此时開始, 请使用静态常量名,这样可以使代码可读。也可以下降对错误码详细数字的依赖. 比方, 不该该用 if (error.code == -2)
而用 if (error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW)
.
错误列表:
NOTHING_TO_INSTALL
- 请求插件安装更新。却没有更新需要安装. 值为 1
.
NOTHING_TO_UPDATE
- 没有可用web更新需要下载.值为 2
.
FAILED_TO_DOWNLOAD_APPLICATION_CONFIG
- 下载新的application config 文件(chcp.json)失败. 要么文件不存在或者网络问题.值为 -1
.
APPLICATION_BUILD_VERSION_TOO_LOW
- 外壳app的build版本过低. 新的web内容需要新的外壳app. 用户需要更新外壳app.值为 -2
.
FAILED_TO_DOWNLOAD_CONTENT_MANIFEST
- 下载内容清单文件(chcp.manifest)失败. 文件chcp.manifest
必须位于 content_url
相应文件夹下, 和chcp.json一块儿.值为 -3
.
FAILED_TO_DOWNLOAD_UPDATE_FILES
- 下载web内容失败. 清单 chcp.manifest
中列出文件的必须都要位于 content_url
相应文件夹下. 还有, 检查各个文件的MD5是否正确. 值为 -4
.
FAILED_TO_MOVE_LOADED_FILES_TO_INSTALLATION_FOLDER
- 移动已下载的文件到安装文件夹时失败. 可能存储空间不足.值为 -5
.
UPDATE_IS_INVALID
- web内容已损坏. 安装以前。插件会检查已下载文件的MD5和 chcp.manifest
中的比較看是否一致. 假设不一致或者文件缺失 - 会发生此错误. 值为 -6
.
FAILED_TO_COPY_FILES_FROM_PREVIOUS_RELEASE
- 从上一版本号拷贝www下文件到新版本号www文件夹出错.可能存储空间不足.值为 -7
.
FAILED_TO_COPY_NEW_CONTENT_FILES
- 拷贝新文件到内容文件夹下失败.可能存储空间不足.值为 -8
.
LOCAL_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND
- 载入本地chcp.json失败. 多是用户手动删除了外部存储的web内容相关文件. 假设发生。会回滚至上移release版本号的web内容.值为 -9
.
LOCAL_VERSION_OF_MANIFEST_NOT_FOUND
-载入本地chcp.manifest失败.多是用户手动删除了外部存储的web内容相关文件. 假设发生。会回滚至上移release版本号的web内容. 值为 -10
.
LOADED_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND
-载入本地已下载的新版本号的chcp.json失败.多是用户手动删除了外部存储的web内容相关文件.假设发生 - app下次启动时会恢复. 值为 -11
.
LOADED_VERSION_OF_MANIFEST_NOT_FOUND
-载入本地已下载的新版本号的chcp.manifest失败.多是用户手动删除了外部存储的web内容相关文件.假设发生 - app下次启动时会恢复.值为 -12
.
FAILED_TO_INSTALL_ASSETS_ON_EXTERNAL_STORAGE
- 拷贝app内置web内容到外部存储时失败.可能存储空间不足. app初次启动时会运行此操做. 假设失败。插件就再也不实用了. 值为 -13
.
CANT_INSTALL_WHILE_DOWNLOAD_IN_PROGRESS
- 调用 chcp.installUpdate
而 插件正在下载更新时触发. 你必须等待完成下载. 值为 -14
.
CANT_DOWNLOAD_UPDATE_WHILE_INSTALLATION_IN_PROGRESS
- 调用 chcp.fetchUpdate
而安装过程在再运行. 你必须等待安装完成. 值为 -15
.
INSTALLATION_ALREADY_IN_PROGRESS
- 调用 chcp.installUpdate
,而安装过程在再运行.值为 -16
.
DOWNLOAD_ALREADY_IN_PROGRESS
- 调用 chcp.fetchUpdate
,而 插件正在下载更新时触发. 值为 -17
.
ASSETS_FOLDER_IN_NOT_YET_INSTALLED
- 调用 chcp
方法, 而插件正在拷贝app内置web内容到外部存储时触发. 仅仅可能在app初次启动时发生. 最后这个错误会被移除.值为 -18
.
好多同窗都測试不成功。你们不要想太复杂了。我再简要归纳一下:
chcp.json文件里的content_url为server项目的地址加port号
config.xml为server项目地址加port号再加上/chcp.json
每次改动完文件后。必须将【改动的文件】和【chcp.manifest文件】一并拷贝到server项目中进行覆盖。
将server中的chcp.json文件里的【"release": "2016.08.04-18.04.06"】时间改成当前时间。
3 和 4是最重要的。否则热更新就不起做用。
最后大家不要在纠结cordova-hcp server,这个东西就是在开发的时候启动用来监听文件的改动。假设有文件改动。就相应在chcp.manifest中改动该文件的hash值。
还没完。为了更清楚的了解热更新是怎么回事,这里我画了一张图。
[热更新的流程解析]
app启动
从server请求chcp.json文件(会覆盖本地chcp.json文件)。
server返回chcp.json文件与app里的chcp.json文件作对照,推断两个文件里的release时间。
假设serverchcp.json文件的release时间大于app里chcp.json的release时间(说明新的资源)
假设有新的资源。再次发送一个请求,请求server的chcp.manifest文件(会覆盖本地chcp.json文件)。
server返回chcp.manifest文件与app里的chcp.manifest文件内容作对照。
假设有不同的hash值。
对server请求新的资源。
请求成功的资源将覆盖本地资源。
这里经过对app进行抓包,来分析热更新是如何进行应用内更新的。注意看1~8。我是没有对server资源进行更新的。直到第9个请求的时候:9。10,11连续发送了3个请求。
[热更新的抓包图]
第9个请求将server的chcp.json文件请求回来后推断时间是大于app的chcp.json时间的
而后发送了第10个请求。chcp.manifest,与本地chcp.manifest文件作对照
当中我仅仅改了一个login.html,因此这里对login.html又一次载入覆盖。
一直有人问我,用不了。不会用之类的。我在这说一下
用 cordova-hcp server 命令启动 hcp 服务器的时候,会看到如上图的local server 和public server,这两个地址是不能自定义的
相似“https://f5f6894c.ngrok.io” 这个地址貌似并没实用,或许仅仅是国内无法用吧
因此。我建议不要用 cordova-hcp server,你需要本身部署一个服务器,托管 www 下的 web 内容
Local Development Add-on 这个扩展也可以不要,记得本身生成新的apk/ipa以前要改config.xml的version(android-versionCode/ios-CFBundleVersion)便可了
事实上 cordova-hcp server 启动的那个服务器。就是多了2个功能:
一、检測到 www 变动后。本身主动生成清单文件 chcp.manifest
二、本身主动实时推送变动到app端
用了你本身的server以后,这2个功能都没了。因此
一、每次更改 www 下的 web 内容以后,必定要手动用 cordova-hcp build(在corodva项目根文件夹下运行), 生成清单文件 chcp.manifest
二、app 仅仅能在每次启动的时候。才干检查有无内容更新。有更新就会在后台下载。等到下次启动 app 才应用更新。
(也就是要从新启动app 2次才干看到效果)
chcp.json 这个文件的内容也要改下,把 update 改成 "start",比方
{ "update": "start", "content_url": "http://10.0.0.100/HCP/", "release": "2016.04.28-10.14.32" }
chcp.json 的功能,不懂的看上面翻译
{ "update": "start", "content_url": "http://10.0.0.100/HCP/" }