原文地址: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 代碼, 圖片等等. 一般有兩種方式進行升級:
-
在appstore中上架新的app. 可是耗時比較長.
-
犧牲全部原生功能。每次打開都從遠端站點載入. 可是假設沒有網絡,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 項目高速向導
-
Ionic 項目?高速向導
-
更新機制的流程圖
-
web內容是怎樣存儲和更新的
-
Cordova Hot Code Push 命令行客戶端
-
本地開發擴展
-
Cordova 配置項
-
配置文件
-
Application config?app配置
-
Content manifest?內容清單
-
Build options?build設置
-
-
JavaScript?模塊
-
監聽更新的事件
-
請求更新
-
安裝更新
-
執行時改變插件設置
-
請求從store更新app(外殼)
-
-
錯誤碼
安裝
須要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 項目, 然后:
-
在?
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, 檢查是否正常.
Cordova 項目高速向導
此向導展示了在開發中怎樣高速使用這個插件. 我們須要加入?開發擴展 。須要?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查看效果.
Ionic 項目高速向導
此向導展示了在開發中怎樣高速使用這個插件. 我們須要加入?開發擴展 。須要?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又一次進入更新過的頁面.
當然, 還有其它的細節, 只是你已經有了大致的思路.
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文件, 發生情況例如以下:
-
在外部存儲創建了一個以新的 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
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 配置項
你應該知道, 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 Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: 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 Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);document.addEventListener('chcp_updateIsReadyToInstall', this.onUpdateReady, false);},// deviceready Event HandleronDeviceReady: function() {console.log('Device is ready for work');},// chcp_updateIsReadyToInstall Event HandleronUpdateReady: 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 Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: 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 Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: 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 Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: function() {// change plugin optionsapp.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).
這里你想怎么做就怎么做. 經常用法是顯示一個對話框,問用戶是否須要轉到應用商店. 插件也提供了這個.
你須要做的是:
-
在 application config(chcp.json) 中設置t?
android_identifier
?和 ?ios_identifier
. -
js端監聽對應事件,并在出現錯誤的時候調用?
chcp.requestApplicationUpdate
?方法.
舉個樣例. 簡單起見我們監聽?chcp_updateLoadFailed
?事件.
var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);document.addEventListener('chcp_updateLoadFailed', this.onUpdateLoadError, false);},// deviceready Event HandleronDeviceReady: 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個功能:
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群:194182999?(滿)
2群:419834979
共同學習交流(博主QQ:479858761)