系統環境 windows 10
所需工具 node.js
, android studio
, 安裝方法自行百度/谷歌
cordova-hot-code-push 不再維護, 轉而使用 cordova-plugin-code-push
安裝 codepush
npm install -g code-push-cli
創建一個 CodePush
的雲賬戶
code-push register
瀏覽器會自動打開窗口進行註冊, 可用 github
帳號登錄, 登錄認證完畢會給一個key
, 在把這個 key
粘貼到剛纔命令行中, 回車註冊完畢
創建 CodePush
應用
假設創建一個 test
安卓應用 (使用命令 code-push app add <appName> <os> <platform>
)
code-push app add test android cordova
創建後生成對應 key
, Production key
和 Staging key
分別爲 生產環境key
和 開發環境key
┌────────────┬──────────────────────────────────────┐
│ Name │ Deployment Key │
├────────────┼──────────────────────────────────────┤
│ Production │ ********** Production key ********** │
├────────────┼──────────────────────────────────────┤
│ Staging │ ********** Staging key ************* │
└────────────┴──────────────────────────────────────┘
*忘記的話可執行命令 code-push deployment ls <appName> -k
查看
安裝 cordova
npm install -g cordova
創建 cordova
應用
cordova create helloworld com.example.hello HelloWorld
helloworld
: 項目文件夾名
com.example.hello
: 項目包名
HelloWorld
: 項目名
添加應用平臺
cd helloworld
cordova platform add android
添加插件
cordova plugin add cordova-plugin-code-push@latest
cordova plugin add cordova-plugin-whitelist
修改 config.xml
, 添加 codepush
生成的 key
<platform name="android">
<preference name="CodePushDeploymentKey" value="********** Staging key or Production key *************" />
</platform>
修改 config.xml
, 允許與CodePush服務器通信
<access origin="*" />
或
<access origin="https://codepush.azurewebsites.net" />
<access origin="https://codepush.blob.core.windows.net" />
<access origin="https://codepushupdates.azureedge.net" />
修改 www/index.html
, 添加 meta
<meta http-equiv="Content-Security-Policy" content="default-src https://codepush.azurewebsites.net 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *" />
修改 www/js/index.js
(js具體使用方法參考文檔: https://github.com/Microsoft/cordova-plugin-code-push)
使用場景爲打開應用有更新則彈窗提示
簡單版:
window.document.addEventListener('deviceready', function () {
// reference: https://github.com/Microsoft/cordova-plugin-code-push#syncoptions
window.codePush.sync(syncStatus, {
updateDialog: true,
installMode: InstallMode.IMMEDIATE,
updateDialog: {
updateTitle: "An update is available!",
optionalUpdateMessage: "Message",
optionalInstallButtonLabel: "Install Button",
optionalIgnoreButtonLabel: "Ignore Button",
}
}, onProgress);
// reference: https://github.com/Microsoft/cordova-plugin-code-push#syncstatus
function syncStatus(status) {
switch (status) {
case SyncStatus.UP_TO_DATE:
console.log("UP_TO_DATE");
break;
case SyncStatus.UPDATE_INSTALLED:
console.log("UPDATE_INSTALLED");
break;
case SyncStatus.UPDATE_IGNORED:
console.log("UPDATE_IGNORED");
break;
case SyncStatus.IN_PROGRESS:
console.log("IN_PROGRESS");
break;
case SyncStatus.CHECKING_FOR_UPDATE:
console.log("CHECKING_FOR_UPDATE");
break;
case SyncStatus.AWAITING_USER_ACTION:
console.log("AWAITING_USER_ACTION");
break;
case SyncStatus.DOWNLOADING_PACKAGE:
console.log("DOWNLOADING_PACKAGE");
break;
case SyncStatus.INSTALLING_UPDATE:
console.log("INSTALLING_UPDATE");
break;
case SyncStatus.ERROR:
console.log("ERROR");
break;
}
}
function onProgress(downloadProgress) {
console.log("Downloading " + downloadProgress.receivedBytes + " of " + downloadProgress.totalBytes + " bytes.");
};
})
複雜版:
var app = {
initialize: function () {
this.bindEvents();
},
bindEvents: function () {
window.document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
// reference: https://github.com/Microsoft/cordova-plugin-code-push#syncoptions
window.codePush.sync(app.syncStatus, {
updateDialog: true,
installMode: InstallMode.IMMEDIATE,
updateDialog: {
updateTitle: "An update is available!",
optionalUpdateMessage: "Message",
optionalInstallButtonLabel: "Install Button",
optionalIgnoreButtonLabel: "Ignore Button",
}
}, app.downloadProgress);
},
// reference: https://github.com/Microsoft/cordova-plugin-code-push#syncstatus
syncStatus: function(status) {
switch (status) {
case SyncStatus.UP_TO_DATE:
console.log("UP_TO_DATE");
break;
case SyncStatus.UPDATE_INSTALLED:
console.log("UPDATE_INSTALLED");
break;
case SyncStatus.UPDATE_IGNORED:
console.log("UPDATE_IGNORED");
break;
case SyncStatus.IN_PROGRESS:
console.log("IN_PROGRESS");
break;
case SyncStatus.CHECKING_FOR_UPDATE:
console.log("CHECKING_FOR_UPDATE");
break;
case SyncStatus.AWAITING_USER_ACTION:
console.log("AWAITING_USER_ACTION");
break;
case SyncStatus.DOWNLOADING_PACKAGE:
console.log("DOWNLOADING_PACKAGE");
break;
case SyncStatus.INSTALLING_UPDATE:
console.log("INSTALLING_UPDATE");
break;
case SyncStatus.ERROR:
console.log("ERROR");
break;
}
},
downloadProgress: function(downloadProgress) {
console.log("Downloading " + downloadProgress.receivedBytes + " of " + downloadProgress.totalBytes + " bytes.");
},
};
app.initialize();
詢問CodePush服務配置的應用程序部署是否有可用的更新, 場景爲點擊 '檢查更新' 按鈕觸發事件
簡單版:
window.document.addEventListener('deviceready', function () {
console.log('deviceready');
window.codePush.notifyApplicationReady(onNotifySucceeded, onNotifyFailed);
window.codePush.checkForUpdate(onUpdateCheck, onError);
function onError(error) {
console.log("An error occurred. " + error);
};
function onInstallSuccess() {
console.log("Installation succeeded.");
};
function onNotifySucceeded() {
console.log("NotifySucceeded.");
};
function onNotifyFailed(error) {
console.log("NotifyFailed. " + error);
}
function onPackageDownloaded(localPackage) {
console.log("Package downloaded at: " + localPackage.localPath);
console.log("localPackage appVersion: " + localPackage.appVersion);
console.log("localPackage description: " + localPackage.description);
console.log("localPackage failedInstall: " + localPackage.failedInstall);
console.log("localPackage isFirstRun: " + localPackage.isFirstRun);
console.log("localPackage isMandatory: " + localPackage.isMandatory);
// InstallMode.IMMEDIATE: 立即更新APP
// InstallMode.ON_NEXT_RESTART: 到下一次啓動應用時更新
// InstallMode.ON_NEXT_RESUME: 當應用從後臺返回時更新
localPackage.install(onInstallSuccess, onError, { installMode: InstallMode.ON_NEXT_RESUME, mandatoryInstallMode: InstallMode.ON_NEXT_RESTART });
};
function onProgress(downloadProgress) {
console.log("Downloading " + downloadProgress.receivedBytes + " of " + downloadProgress.totalBytes + " bytes.");
};
function onUpdateCheck(remotePackage) {
if (!remotePackage) {
console.log("The application is up to date.");
} else {
// The hash of each previously reverted package is stored for later use.
// This way, we avoid going into an infinite bad update/revert loop.
if (!remotePackage.failedInstall) {
console.log("There is an update available. Remote package:" + JSON.stringify(remotePackage));
console.log("A CodePush update is available. Package hash: " + remotePackage.packageHash);
remotePackage.download(onPackageDownloaded, onError, onProgress);
} else {
console.log("The available update was attempted before and failed.");
}
}
};
})
複雜版:
var app = {
initialize: function () {
this.bindEvents();
},
bindEvents: function () {
window.document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
app.notifyApplicationReadys();
app.checkForUpdates();
},
notifyApplicationReadys: function() {
var onNotifySucceeded = function() {
console.log("NotifySucceeded.");
};
var onNotifyFailed = function(error) {
console.log("NotifyFailed. " + error);
};
window.codePush.notifyApplicationReady(onNotifySucceeded, onNotifyFailed);
},
checkForUpdates: function() {
var onInstallSuccess = function() {
console.log("Installation succeeded.");
};
var onUpdateCheck = function(remotePackage) {
if (!remotePackage) {
console.log("The application is up to date.");
} else {
// The hash of each previously reverted package is stored for later use.
// This way, we avoid going into an infinite bad update/revert loop.
if (!remotePackage.failedInstall) {
console.log("There is an update available. Remote package:" + JSON.stringify(remotePackage));
console.log("A CodePush update is available. Package hash: " + remotePackage.packageHash);
remotePackage.download(onPackageDownloaded, app.onError, onProgress);
} else {
console.log("The available update was attempted before and failed.");
}
}
};
var onPackageDownloaded = function(localPackage) {
console.log("Package downloaded at: " + localPackage.localPath);
console.log("localPackage appVersion: " + localPackage.appVersion);
console.log("localPackage description: " + localPackage.description);
console.log("localPackage failedInstall: " + localPackage.failedInstall);
console.log("localPackage isFirstRun: " + localPackage.isFirstRun);
console.log("localPackage isMandatory: " + localPackage.isMandatory);
console.log("localPackage packageSize: " + localPackage.packageSize);
// InstallMode.IMMEDIATE: 立即更新APP
// InstallMode.ON_NEXT_RESTART: 到下一次啓動應用時更新
// InstallMode.ON_NEXT_RESUME: 當應用從後臺返回時更新
localPackage.install(onInstallSuccess, app.onError, { installMode: InstallMode.ON_NEXT_RESUME, mandatoryInstallMode: InstallMode.ON_NEXT_RESTART });
};
var onProgress = function(downloadProgress) {
console.log("Downloading " + downloadProgress.receivedBytes + " of " + downloadProgress.totalBytes + " bytes.");
};
window.codePush.checkForUpdate(onUpdateCheck, app.onError);
},
onError: function(error) {
console.log("An error occurred. " + error);
},
};
app.initialize();
編譯產出 apk
, 產出路徑 platforms/android/app/build/outputs/apk/debug/app-debug.apk
cordova build
手機安裝產出的 apk
應用
或者使用 android studio
導入 platforms/android
代碼, 添加一個 Virtual Device
進行測試 (推薦)
發佈更新
code-push release-cordova test android -d "Staging" --des "描述"
Usage: code-push release-cordova <appName> <platform> [options]
Options:
--deploymentName, -d 指定部署的類型, 默認"Staging", 可以選擇"Production"
--description, --des 添加描述
--disabled, -x 指定是否應立即下載此版本
--mandatory, -m 指定此版本是否爲強制更新版本
--targetBinaryVersion, -t 指定需要更新的版本號, 如果省略, 則用 config.xml 裏的版本號 (例如 1.1.0, ~1.2.3)
例1: 發佈android應用更新
code-push release-cordova <appName> android --des "描述"
例2: 部署android應用生產環境的熱更新
code-push release-cordova <appName> android -d "Production" --des "描述"
例3: 部署ios應用的強制更新
code-push release-cordova <appName> ios -m --des "描述"
例4: 版本號>=1.2.3和<1.3.0的android應用更新
code-push release-cordova <appName> android --des "描述" -t ~1.2.3
查看發佈狀態
# code-push deployment ls test
┌────────────┬─────────────────────────────┬──────────────────────┐
│ Name │ Update Metadata │ Install Metrics │
├────────────┼─────────────────────────────┼──────────────────────┤
│ Production │ No updates released │ No installs recorded │
├────────────┼─────────────────────────────┼──────────────────────┤
│ Staging │ Label: v2 │ Active: 40% (2 of 5) │
│ │ App Version: 1.0.0 │ Total: 2 │
│ │ Mandatory: No │ │
│ │ Release Time: 1 minute ago │ │
│ │ Released By: │ │
│ │ Description: 描述 │ │
└────────────┴─────────────────────────────┴──────────────────────┘
// 給app在熱更新服務器上創建應用
code-push app add <appName> <os> <platform>
例: code-push app add <appName> android cordova
// 刪除應用
code-push app rm <appName>
// 查看熱更新服務器上有哪些應用
code-push app list
// 查看部署狀態
code-push deployment ls <appName>
// 查看部署狀態及key值
code-push deployment ls <appName> -k
// 清空部署記錄
code-push deployment clear <appName> <deploymentName>
例: 清空Staging狀態的部署記錄
code-push deployment clear <appName> Staging
// 刪除自定義的部署狀態
code-push deployment rm <appName> <deploymentName>
參考:
https://github.com/Microsoft/cordova-plugin-code-push
https://segmentfault.com/a/1190000008591456
https://www.jianshu.com/p/6bbb8020c29e