【Ionic】Ionic實現iOS與Android端程式碼『熱更新』與Android升級下載功能 ( v1.3.x版本 )
熱更新的好處
通常ionic原始碼可包括(HTML,JavaScript,CSS檔案和其他資源),往常我們必須通過提交程式到應用市場,經過漫長的稽核後才可讓使用者更新,每改動一個小地方都需要重新打新版本。
現在ionic通過使用cordova外掛cordova-hot-code-push實現實現iOS與Android端程式碼『熱更新』功能,可不必釋出應用市場經平臺稽核,便可動態更新App原始碼的目的。
熱更新實現原理
基礎實現方法
1、安裝 cordova-hot-code-push-cli
使用命令安裝
npm install -g cordova-hot-code-push -cli
主要是生成檢測配置檔案,通常是在 www 目錄下動態生成 chcp.json 和 chcp.manifest 生成兩個檔案,外掛原始碼地址:
2、建立專案
包含 www 目錄的專案,已有專案無需重新建立
3、安裝熱更新外掛
使用命令安裝
ionic plugin add cordova-hot-code-push-plugin
ionic plugin add cordova-hot-code-push-local-dev-addon
4、打包封裝
執行命令cordova-hcp build 或者 cordova build
5、啟動 hcp server 服務
重新開啟一個終端視窗,cd到專案目錄(包含www目錄的父級目錄)執行命令
cordova-hcp server
稍等會在 www 目錄下動態生成 chcp.json 和 chcp.manifest 生成兩個檔案
6、正常在執行完成前4步以後會在我們config.xml動態加入如圖所示連結地址
7、執行程式碼或打包我們的App
8、修改我們想要更新的程式碼
然後修改 chcp.json 檔案的 content_url ,此地址為我們專案放置的地址
{
"autogenerated": true,
"release": "2016.07.17-11.36.13" ,
"content_url": "http://kaibin.me/hotcode",
"update": "now"
}
9、將專案www目錄程式碼上傳到伺服器可訪問的目錄裡
例如在伺服器根目錄建立hotcode命名的目錄將專案www裡的檔案上傳上去
10、 關閉我們的應用重新開啟,看看程式碼是否更新成功
**優化流程
1.建立cordova-hcp模板**
線上測試可解除安裝掉 cordova-hot-code-push-local-dev-addon防止每次自動更新新版本,可通過命令解除安裝:
cordova plugin remove cordova-hot-code-push-local-dev-addon
可以在 cordova 專案根目錄下放一個 cordova-hcp.json,這是個模板檔案
這樣每次執行
cordova-hcp build
就會利用這個模板生成新的 chcp.json,而不用手動更改 www/chcp.json了。
cordova-hcp.json內容如下:
{
"autogenerated": true,
"content_url": "http://kaibin.me/hotcode",
"min_native_interface": 1, // app核心版本號
"ios_identifier": "https://itunes.apple.com/cn/app/***", // iOS上線後的地址,用於核心版本更新後的確認跳轉
"update": "now"
}
2.Build options build設定,配置開發環境、測試環境與生產環境
在 /Cordova/Testproject/ 下建立 chcpbuild.options 檔案,檔案內容如下:
{
"dev": {
"config-file": "https://dev.kaibin.me/hotcode/www/chcp.json"
},
"production": {
"config-file": "https://kaibin.me/hotcode/chcp.json"
},
"QA": {
"config-file": "https://test.kaibin.me/hotcode/chcp.json"
}
}
這樣在build app的時候, 轉為開發要用的伺服器, 可執行:
ionic build -- chcp-dev
結果就是, 特定拍下的 config.xml 檔案(比如, /Cordova/TestProject/platforms/android/res/xml/config.xml) 變成了這樣:
<chcp>
<config-file url="https://dev.kaibin.me/hotcode/chcp.json"/>
</chcp>
當我們需要上架app的時候 (Google Play, App Store) - 我們正常build:
ionic build --release
這樣 config.xml 不會改變
如果沒有使用 chcpbuild.options 外掛會使用 config.xml 裡面預設的值。
檔案必須位於 Cordova 專案根目錄. 在這個檔案裡面,指定(JSON格式) 所有想改變 config.xml 檔案的配置,原始檔 config.xml (Cordova專案根目錄) 不會發生變動, 改變的是 特定平臺下的 config.xml (在cordova build過程的 after_prepare 階段)。
通過min_native_interface監控app是否提示更新
所需最小的外殼app版本. 這是app的build版本號,是個整型數字, 不是應用商店中看到的形如”1.0.0”字串。
在 config.xml中,這樣指定build版本號:
<chcp>
<native-interface version="1"/>
<config-file url="http://kaibin.me/hotcode/chcp.json"/>
</chcp>
與www目錄下的chcp.json裡面的min_native_interface數值相對應
例如:app外殼裡的config.xml是這樣的:
<chcp>
<native-interface version="1"/>
<config-file url="http://kaibin.me/hotcode/chcp.json"/>
</chcp>
若伺服器裡的min_native_interface也對應是1,不會出現提示使用者升級的狀態,正常修改www目錄的內容通過更新release值,可實現熱更新。
{
"autogenerated": true,
"content_url": "http://kaibin.me/hotcode",
"min_native_interface": 1, // app核心版本號
"ios_identifier": "https://itunes.apple.com/cn/app/***", // iOS上線後的地址,用於核心版本更新後的確認跳轉
"release": "2017.07.17-12.22.11",
"update": "now"
}
假設你的外殼app加了個新的外掛,應該會更新外殼app。為了防止使用者通過熱更新下載了不適合他現有外殼app的web內容,你應該設定 min_native_interface 這個值
{
"autogenerated": true,
"content_url": "http://kaibin.me/hotcode",
"min_native_interface": 1, // app核心版本號
"ios_identifier": "https://itunes.apple.com/cn/app/***", // iOS上線後的地址,用於核心版本更新後的確認跳轉
"release": "2017.07.17-12.28.21",
"min_native_interface": 2,
"update": "now"
}
外掛載入到這段json的時候, 發現 min_native_interface 比當前外殼app的build號要大,便不會下載web內容。而是觸發一個chcp_updateLoadFailed 錯誤通知, 告訴使用者需要升級外殼app了。
chcp.json中update欄位含義
指定了什麼時候安裝web內容更新,支援的值有:
start - app啟動時安裝更新,預設值
resume - app從後臺切換過來的時候安裝更新
now - web內容下載完畢即安裝更新
引導使用者去應用商店更新外殼app或下載新版本
通過給web更新設定最小支援的外殼app版本 min_native_interface。 如果外掛檢查發現使用者安裝的外殼app版本比服務端新的web內容要求的版本要低,就會觸發錯誤事件,錯誤碼:
chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW
通過這個錯誤碼可通過彈窗提示使用者去升級,跳轉到AppStore或下載新安裝包(國內因GFW,跳轉到google應用商店就算了= =)
chcp.json 裡增加min_native_interface的值
js端監聽相應事件,並在出現錯誤的時候呼叫 chcp.requestApplicationUpdate 方法
cordova-plugin-file,cordova-plugin-file-transfer,cordova-plugin-file-opener2先把這幾個外掛安裝好
var appUpdate = {
// 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) {
var dialogMessage = '有新的版本,請下載更新';
// iOS端 直接彈窗提示升級,點選ok後自動跳轉
if(ionic.Platform.isIOS()){
chcp.requestApplicationUpdate(dialogMessage, this.userWentToStoreCallback, this.userDeclinedRedirectCallback);
// Android端 提示升級下載最新APK檔案
}else if(ionic.Platform.isAndroid()){
var confirmPopup = $ionicPopup.confirm({
template: '有新的版本,請下載更新',
cssClass: 'popup',
cancelText:'取消',
okText:'升級'
});
confirmPopup.then(function (res) {
if (res) {
$ionicLoading.show({
template: "已經下載:0%"
});
window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function(fileEntry) {
fileEntry.getDirectory("***(app名稱)", { create: true, exclusive: false }, function (fileEntry) {
//下載程式碼
var fileTransfer = new FileTransfer();
fileTransfer.download("app下載地址", fileEntry.toInternalURL()+"***(app名稱).apk", function(entry) {
// 開啟下載下來的APP
cordova.plugins.fileOpener2.open(
entry.toInternalURL(),//下載檔案儲存地址
'application/vnd.android.package-archive', {//以APK檔案方式開啟
error: function(err) {
},
success: function() {}
});
}, function(err) {
},true);
fileTransfer.onprogress = function(progressEvent) {
$timeout(function () {
var downloadProgress = (progressEvent.loaded / progressEvent.total) * 100;
$ionicLoading.show({
template: "已經下載:" + Math.floor(downloadProgress) + "%"
});
if (downloadProgress > 99) {
$ionicLoading.hide();
}
});
};
},function(err){alert("建立失敗")});
});
}
});
}
}
},
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.
}
};
appUpdate.initialize();
iOS與Android的出現的問題
在build ios的app時config.xml的
<name>***</name>
name不可使用中文,設定app名稱為中文,可通過Xcode修改Resources目錄下的*-Info.plist內的Bundle display name欄位即可