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