[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

时间:2022-08-31 20:27:03

原文地址:http://blog.csdn.net/lovelyelfpop/article/details/50848524

插件地址:https://github.com/nordnet/cordova-hot-code-push

以下是我对GitHub项目readme的翻译

——————————————————————————————————————————————

Cordova
Hot Code Push Plugin

此插件提供了能够使cordova app自己主动更新web内容的功能。

​基本上, 你App中全部位于 www 文件夹内的文件都能够被自己主动更新.

当你又一次公布新的app时-又一次打包了web内容: html 文件, JavaScript 代码, 图片等等. 一般有两种方式进行升级:

  1. 在appstore中上架新的app. 可是耗时比較长.

  2. 牺牲全部原生功能。每次打开都从远端站点载入. 可是假设没有网络,app就没法使用.

此插件就为了解决问题而生. 当用户初次打开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,
仅仅是用了它会更加方便.

从低版本号迁移

从 v1.0.x 到 v1.1.x

在版本号 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 项目, 然后:

  1. 在 Build Settings,设置 Embedded
    Content Contains Swift Code
     为 NO.

  2. 打开 <YOUR_PROJECT_NAME>-Prefix.pch , 移除 #import
    <YOUR_PROJECT_NAME>-Swift.h
    . 比方:

    #ifdef __OBJC__
    #import "TestProject-Swift.h"
    #endif
  3. 又一次build, 检查是否正常.

Cordova
项目高速向导

此向导展示了在开发中怎样高速使用这个插件. 我们须要加入 开发扩展 。须要 Xcode 7, 虽然hot
code push plugin插件自身能够支持低版本号xcode.

  1. 创建新的Cordova项目。并加入android和iOS platform:

    cordova create TestProject com.example.testproject TestProjectcd ./TestProject
    cordova platform add android
    cordova platform add ios

    或者能够用一个已有的项目.

  2. 加入插件:

    cordova plugin add cordova-hot-code-push-plugin
  3. 加入开发扩展:

    cordova plugin add cordova-hot-code-push-local-dev-addon
  4. 安装 Cordova Hot Code Push 命令行client:

    npm install -g cordova-hot-code-push-cli
  5. 启动本地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
  6. 打开新的控制台, 进入到项目根文件夹,执行app:

    cordova run

    稍等,app会安装到手机或者模拟器.

  7. 如今打开 TestProject/www/index.html ,
    做一些修改然后保存. 几秒种后你能够在手机或模拟器上看到更新后的页面.

到此,你能够本地开发。新的web内容会自己主动在设备上更新,而无需又一次启动app查看效果.

Ionic
项目高速向导

此向导展示了在开发中怎样高速使用这个插件. 我们须要加入 开发扩展
。须要 Xcode
7, 虽然hot
code push plugin插件自身能够支持低版本号xcode.

  1. 创建新的Ionic项目,并加入android和iOS
    platform::

    ionic start TestProject blankcd ./TestProject
    ionic platform add android
    ionic platform add ios

    Or use the existing one.

  2. 加入插件:

    ionic plugin add cordova-hot-code-push-plugin
  3. 加入开发扩展:

    ionic plugin add cordova-hot-code-push-local-dev-addon
  4. 安装 Cordova
    Hot Code Push 命令行client:

    npm install -g cordova-hot-code-push-cli
  5. 启动本地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
  6. 打开新的控制台,
    进入到项目根文件夹。执行app:

    ionic run

    稍等。app会安装到手机或者模拟器.

  7. 如今打开 TestProject/www/index.html ,
    做一些修改然后保存. 几秒种后你能够在手机或模拟器上看到更新后的页面.

到此,你能够本地开发,新的web内容会自己主动在设备上更新。而无需又一次启动app查看效果.

更新机制的流程图

先防止全部的配置相关的内容弄得你稀里糊涂 - 先来看看此插件的实现更新功能的流程图. 应该没有技术细节.

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

  1. 用户打开你的app.

  2. 插件初始化,在后台进程启动 升级载入器(update loader).

  3. Update loader  从 config.xml 取 config-file 配置(一个url),并从此url载入一段
    JSON 配置.  然后它把这段JSON配置中的 release 版本 和当前app 已经安装的进行比較. 假设不同 - 进入下一步.

  4. Update loader 使用app配置(application config)中的 content_url 。去载入清单文件(manifest).
    它会找出自上次升级以来,哪些文件须要更新.

  5. Update loader 从 content_url下载更新文件.

  6. 假设一切顺利 - 发出一个"升级文件已经准备好,能够安装了"的通知.

  7. 升级文件已安装, app又一次进入更新过的页面.

当然, 还有其它的细节, 只是你已经有了大致的思路.

web内容是怎样存储和更新的

每个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文件, 发生情况例如以下:

  1. 在外部存储创建了一个以新的 release 版本为名字的文件夹: /sdcard/some_path/2016.01.03-10.45.01/.

  2. 文件夹里面 - 又创建了一个 update 文件夹 : /sdcard/some_path/2016.01.03-10.45.01/update/.

  3. 全部依据 chcp.manifest 更新的文件 都被下载到了这个 update 文件夹内.

  4. 新的 chcp.manifest 和 chcp.json 也被放到了 update 文件夹内.

  5. 新的web内容已准备安装.

安装更新的时候:

  1. 插件从当前正在使用的release版本号 文件夹内拷贝 www 下全部内容到 新的 release 版本号文件夹下. 用我们的样例就是:从 /sdcard/some_path/2015.12.01-12.01.33/www/ 拷贝全部文件到 /sdcard/some_path/2016.01.03-10.45.01/www/.

  2. update 文件夹下拷贝新的web内容和配置文件,到 www 文件夹下: /sdcard/some_path/2016.01.03-10.45.01/update/ -> /sdcard/some_path/2016.01.03-10.45.01/www/.

  3. 移除 /sdcard/some_path/2016.01.03-10.45.01/update/ 文件夹。由于我们不再使用了.

  4. 载入新的release版本号index.html: /sdcard/some_path/2016.01.03-10.45.01/www/index.html.

至此。插件会从新的release载入页面, 而旧的release则会作为一个备份留下来,以防万一.

Cordova
Hot Code Push 命令行client

Cordova Hot Code Push 命令行client 是一个命令行工具,以便你web内容的开发.

它能够:

  • 生成 chcp.json 和 chcp.manifest 文件,
    这样你就不用手动去创建;

  • 执行本地服务,开发时能够检測更新,并公布新的release版本号,使得能够再设备上实时更新web内容;

  • 部署你的web内容到外部server上.

当然, 你能够不使用这个命令行工具. 仅仅是用了它会更方便一些.

本地开发扩展

当你本地开发app时 - 一般做法类似:

  1. web项目做一些更改.

  2. 运行 cordova run 启动app.

  3. 稍等一会查看执行结果.

即使非常小的变更也须要打包重装app. 耗时比較久,比較麻烦.

为了提升速度 - 你能够使用本地开发扩展 Hot Code Push Local Development Add-on. 安装非常简答:

  1. 加入此cordova插件.

  2. 启动本地服务 cordova-hcp server.

  3. 在你的项目的config.xml 文件里 <chcp
    />
     块下加入 <local-development
    enabled="true" />
    .

  4. 启动app.

这样, 全部web内容的变更都会被插件检測到, 并直接更新显示到app上,而不须要重新启动app.

仅仅有在加入了新的cordova插件时你才会重新启动app.

重要: 你应该仅仅在开发状态下使用此扩展. 公布外壳app的时候,应该移除此扩展: cordova plugin remove cordova-hot-code-push-local-dev-addon.

Cordova
配置项

你应该知道, Cordova 使用 config.xml 文件配置不同项目: app名字, 描写叙述, 起始页面,等等. 使用config.xml文件。你也能够为此插件配置.

这些配置位于 <chcp> 块. 比方:

<chcp>
<config-file url="https://5027caf9.ngrok.com/chcp.json"/>
</chcp>
config-file

定义了一个 URL。指定了须要从哪里载入app配置(application config,就是chcp.json). URL 在 url 属性中声明. 此项必须.

以防万一,开发的时候, 假设 config-file 未定义 - 会自己主动设为本地服务上 chcp.json 的路径.

auto-download

自己主动下载web内容更新. 默认是自己主动, 假设你想手动下载web内容更新,你能够使用 JavaScript 模块(以下有).

禁用自己主动下载能够设置 config.xml:

<chcp>
<auto-download enabled="false" />
</chcp>

默认是 true.

auto-install

自己主动安装.
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
 命令时指定插件的配置.

Application config app配置

包括最新版本号的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的文档.

content_url

服务端URL, 也就是你全部web内容文件的位置. 插件会把它作为下载新的清单文件、新的web内容文件的 base url. 此项必须.

release

不论什么字符串. 每次release应该唯一. 插件基于这个才知道有没有新版本号release. 此项必须.

重要: 插件仅仅比較release字符串是否相等, 假设不等,就觉得服务端有新版本号.(不会比較大小)

min_native_interface

所需最小的外壳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、2、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 . 假设须要以后能够支持.

update

指定了什么时候安装web内容更新. 支持的值有:

  • start - app启动时安装更新. 默认值.

  • resume - app从后台切换过来的时候安装更新.

  • now - web内容完成下载即安装更新.

你能够用JavaScript禁止自己主动安装. 请看 JavaScript
module
 小节.

android_identifier

apk包名. 假设指定了 - 引导用户到 Google Play Store 的app页面.

ios_identifier

ios应用标识号, 比方: id345038631. 假设指定了 - 引导用户到 App Store 的app页面.

Content manifest内容清单

内容清单描写叙述了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
file

相对于 www 的路径(就是你存放web内容的地方).

比方, 你的web内容位于:  /Workspace/Cordova/TestProject/www.  你的 file 值应该是相对于这个路径.

hash

文件的 MD5 值. 用于检測自上次release以来。这个文件是否变更过. 还实用于检測app端下载的文件是否出错.

建议: 每次变更web内容后都应该更新 chcp.manifest 文件. 否则插件不会检測到不论什么更新.

Build options build设置

就像在 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 里面默认的值.

JavaScript 模块

默认情况下, 全部的 检查更新->下载->安装 过程都是插件在原生端自己主动进行的. 不须要其他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, 按下它能够检查更新. 我们须要这样写代码:

  1. 监听button的 click 事件.

  2. 当点击button时调用chcp.fetchUpdate() .

  3. 处理更新事件的结果.

我们来改 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 回调里处理了,相关的更新事件还是会触发并广播的.

安装web更新

调用:

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更新.
此时, 我们应该这样:

  1. 公布新版本号的web内容, 它们能够用于最初的 config-file url.

  2. 在新的版本号 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();

引导用户去应用商店更新外壳app

从 Application config app配置 小节我们知道。能够给web更新设置最小支持的外壳app版本号
(min_native_interface ). 假设插件检查发现用户安装的外壳app版本号比服务端新的web内容要求的版本号要低 - 就会触发错误事件。错误码chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW.
通过这个错误码我们能够引导用户去应用商店更新外壳app (Google Play /App Store).

这里你想怎么做就怎么做. 经常用法是显示一个对话框,问用户是否须要转到应用商店. 插件也提供了这个.

你须要做的是:

  1. 在 application config(chcp.json) 中设置t android_identifier 和  ios_identifier.

  2. 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.


关于热更新的流程解析

好多同学都測试不成功。大家不要想太复杂了。我再简要概括一下:

  1. chcp.json文件里的content_url为server项目的地址加port号

  2. config.xml为server项目地址加port号再加上/chcp.json

  3. 每次改动完文件后。必须将【改动的文件】和【chcp.manifest文件】一并拷贝到server项目中进行覆盖。

  4. 将server中的chcp.json文件里的【"release": "2016.08.04-18.04.06"】时间改为当前时间。

3 和 4是最重要的。不然热更新就不起作用。

最后你们不要在纠结cordova-hcp server,这个东西就是在开发的时候启动用来监听文件的改动。假设有文件改动。就相应在chcp.manifest中改动该文件的hash值。

还没完。为了更清楚的了解热更新是怎么回事,这里我画了一张图。

[热更新的流程解析]

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

  1. app启动

  2. 从server请求chcp.json文件(会覆盖本地chcp.json文件)。

  3. server返回chcp.json文件与app里的chcp.json文件做对照,推断两个文件里的release时间。

  4. 假设serverchcp.json文件的release时间大于app里chcp.json的release时间(说明新的资源)

  5. 假设有新的资源。再次发送一个请求,请求server的chcp.manifest文件(会覆盖本地chcp.json文件)。

  6. server返回chcp.manifest文件与app里的chcp.manifest文件内容做对照。

  7. 假设有不一样的hash值。

  8. 对server请求新的资源。

  9. 请求成功的资源将覆盖本地资源。

案例

这里通过对app进行抓包,来分析热更新是如何进行应用内更新的。注意看1~8。我是没有对server资源进行更新的。直到第9个请求的时候:9。10,11连续发送了3个请求。

[热更新的抓包图]

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

  • 第9个请求将server的chcp.json文件请求回来后推断时间是大于app的chcp.json时间的

  • 然后发送了第10个请求。chcp.manifest,与本地chcp.manifest文件做对照

  • 当中我仅仅改了一个login.html,所以这里对login.html又一次载入覆盖。


一直有人问我,用不了。不会用之类的。我在这说一下

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

用 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个功能:

1、检測到 www 变更后。自己主动生成清单文件 chcp.manifest

2、自己主动实时推送变更到app端



用了你自己的server之后,这2个功能都没了。所以

1、每次更改 www 下的 web 内容之后,一定要手动用 cordova-hcp build(在corodva项目根文件夹下运行), 生成清单文件 chcp.manifest

2、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 的功能,不懂的看上面翻译

能够在 cordova 项目根文件夹下放一个 cordova-hcp.json,这是个模板文件

这样每次运行 cordova-hcp build, 就会利用这个模板生成新的 chcp.json,而不用手动更改 www/chcp.json了。

cordova-hcp.json内容例如以下:

{
"update": "start",
"content_url": "http://10.0.0.100/HCP/"
}

常见问题解决的方法:

1、假设用安卓模拟器測试的,请确保手机模拟器的时区、时间和server时区、时间一致。否则。版本对不上。就检測不到更新了

欢迎增加Sencha Touch + Phonegap交流群

1群:

idkey=d578312312c7dd1a7cbf0f7b7080a40feb21843740c29e2e5588f1987e95267a" style="color:rgb(202,0,0); text-decoration:none">194182999

 (满)

2群:419834979

共同学习交流(博主QQ:

v=3&uin=479858761&site=qq&menu=yes" style="color:rgb(202,0,0); text-decoration:none">479858761

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容的更多相关文章

  1. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发76 让cordova app訪问远端站点也能调用cordova插件功能

    原文链接:http://blog.csdn.net/lovelyelfpop/article/details/50735395 我相信.应该会有一些cordova开发人员想过实现以下这种app: 使用 ...

  2. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发36 Phonegap&sol;Cordova项目的图标和启动画面&lpar;splashscreen&rpar;配置

    原文地址:http://blog.csdn.net/lovelyelfpop/article/details/40780111 Phonegap/Cordova项目中的config.xml文件.里面配 ...

  3. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发29 安卓navigator&period;camera&period;getPicture得到图片的真实路径

    原文地址:http://blog.csdn.net/lovelyelfpop/article/details/38313021 phonegap的拍照插件选择图库中的图片.代码例如以下: naviga ...

  4. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发19 某些安卓手机上弹出消息框 点击后不消失的解决的方法

    Ext.Msg.alert等弹出框在某些安卓手机上,点击确定后不消失. 原因是: 消息框点击确定后有一段css3 transform动画,动画完毕后才会隐藏(display:none). 有些奇葩手机 ...

  5. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发72 List列表横向滑动操作(仿QQ列表滑动删除)

    原文链接:http://blog.csdn.net/lovelyelfpop/article/details/50425744 本插件有2个版本号:sencha touch 版本号和 extjs6 m ...

  6. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发34 gem安装compass,不编译scss,怎么办?

    很多人已经发现,今天,该命令 "gem install compass" 安装compass,正在使用 "compass compile" 编scss的时间将报 ...

  7. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发24 包wp8&period;1的App,弹出软键盘输入框聚焦实施后,无移动采收率方法来解决接口

    这种现象不仅是现在显示phonegap包sencha touch的wp8.1该程序将出现(只wp8.1,wp8正常).其他js我测试了几个框架(app framework, jquery mobile ...

  8. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发24 打包wp8&period;1的App,执行时输入框聚焦弹出软键盘之后,界面上移而不恢复原位的解决的方法

    这个现象仅仅出如今phonegap打包sencha touch的wp8.1程序会出现(仅wp8.1,wp8正常),其他js框架我測试了几个(app framework, jquery mobile), ...

  9. &lbrack;Phonegap&plus;Sencha Touch&rsqb; 移动开发26 Android下的sencha touch程序,转屏时,Ext&period;Viewport不能触发orientationchange事件的解决的方法

    Sencha touch 2.4.2 已经解决问题了. 比方你为Ext.Viewport的orientationchange事件加入了一个监听方法: Ext.Viewport.on('orientat ...

随机推荐

  1. Spark 宏观架构&amp&semi;执行步骤

    Spark 使用主从架构,有一个中心协调器和许多分布式worker. 中心协调器被称为driver.Driver 和被称为executor 的大量分布式worker 通信 Driver 运行在它自己的 ...

  2. 搭建Nuget

    1.  新建一个 ASP.NET 空Web应用程序 2. 在新建的项目中引用 安装 NuGet.Server 2.1 右键项目中的引用,出现一个“管理NuGet程序包(N)”,点击进入 2.2  在搜 ...

  3. mysql中select into 和sql中的select into 对比

    现在有张表为student,我想将这个表里面的数据复制到一个为dust的新表中去.answer 01: create table dust select * from student;//用于复制前未 ...

  4. CSS Sprites&lpar;基本写法,怎样使用&rpar;

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/XTQueen_up/article/details/37601361 说白就是用样式表切一个大图片 ...

  5. fastreport好象将想合并哪个单元就将那一列的TEXT控件的Merge的属性设成True就可以了

    好象将想合并哪个单元就将那一列的TEXT控件的Merge的属性设成True就可以了 可以用FASTREPORT中的分组打印,你看一下里面的DEMO,里面都有的, 高版本的有suppressRepeat ...

  6. avalon2学习教程05属性操作

    avalon2与avalon1的属性操作虽然都是使用ms-attr,但用法完全不一样. avalon1是这样操作属性的 其语法为 ms-attr-valueName="vmProp&quot ...

  7. 【machine translate】deep learning seq2seq

    https://www.tensorflow.org/tutorials/seq2seq https://medium.com/@devnag/seq2seq-the-clown-car-of-dee ...

  8. Phonegap 工作原理

    1.Phonegap是什么 PhoneGap 是一个基于HTML和JavaScript的应用开发平台,使用它可以构建本地应用.你可以把PhoneGap看作一个正方形的web view containe ...

  9. 下载 CentOS 7 镜像文件

    CentOS 7 镜像文件的下载地址 CentOS 官网:https://www.centos.org/ 点击“Get CentOS Now” 点击想要下载的ISO镜像,(目前仅有“DVD ISO”和 ...

  10. 详解ASP&period;NET提取多层嵌套json数据的方法

    本篇文章主要介绍了ASP.NET提取多层嵌套json数据的方法,利用第三方类库Newtonsoft.Json提取多层嵌套json数据的方法,有兴趣的可以了解一下. 本文实例讲述了ASP.NET利用第三 ...