[Phonegap+Sencha Touch] 移動開發77 Cordova Hot Code Push插件實現本身主動更新App的Web內容

原文地址: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

  1. 在appstore中上架新的app. 但是耗時比較長. web

  2. 犧牲所有原生功能。每次打開都從遠端站點載入. 但是假設沒有網絡,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, 僅僅是用了它會更加方便.

從低版本號遷移

從 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查看效果.

更新機制的流程圖

先防止所有的配置相關的內容弄得你稀裏糊塗 - 先來看看此插件的實現更新功能的流程圖. 應該沒有技術細節.


  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、二、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值。

還沒完。爲了更清楚的瞭解熱更新是怎麼回事,這裏我畫了一張圖。

[熱更新的流程解析]


  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個請求。

[熱更新的抓包圖]

  • 第9個請求將server的chcp.json文件請求回來後推斷時間是大於app的chcp.json時間的

  • 而後發送了第10個請求。chcp.manifest,與本地chcp.manifest文件作對照

  • 當中我僅僅改了一個login.html,因此這裏對login.html又一次載入覆蓋。



一直有人問我,用不了。不會用之類的。我在這說一下

用 cordova-hcp server 命令啓動 hcp 服務器的時候,會看到如上圖的local serverpublic 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 的功能,不懂的看上面翻譯


可以在 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/"
}




常見問題解決的方法:

一、假設用安卓模擬器測試的,請確保手機模擬器的時區、時間和server時區、時間一致。不然。版本對不上。就檢測不到更新了








歡迎增長Sencha Touch + Phonegap交流羣

1羣:194182999 (滿)

2羣:419834979

共同窗習交流(博主QQ:479858761

相關文章
相關標籤/搜索