UNPKG

nativescript-code-push

Version:
294 lines (293 loc) 15.8 kB
"use strict"; /// <reference path="./code-push-lib.d.ts"/> Object.defineProperty(exports, "__esModule", { value: true }); var appSettings = require("application-settings"); var AppVersion = require("nativescript-appversion"); var platform_1 = require("tns-core-modules/platform"); var dialogs_1 = require("tns-core-modules/ui/dialogs"); var application = require("tns-core-modules/application"); var TNSAcquisitionManager_1 = require("./TNSAcquisitionManager"); var TNSLocalPackage_1 = require("./TNSLocalPackage"); var TNSRemotePackage_1 = require("./TNSRemotePackage"); var InstallMode; (function (InstallMode) { /** * The update will be applied to the running application immediately. The application will be reloaded with the new content immediately. */ InstallMode[InstallMode["IMMEDIATE"] = "IMMEDIATE"] = "IMMEDIATE"; /** * The update is downloaded but not installed immediately. The new content will be available the next time the application is started. */ InstallMode[InstallMode["ON_NEXT_RESTART"] = "ON_NEXT_RESTART"] = "ON_NEXT_RESTART"; /** * The update is downloaded but not installed immediately. The new content will be available the next time the application is resumed or restarted, whichever event happends first. */ InstallMode[InstallMode["ON_NEXT_RESUME"] = "ON_NEXT_RESUME"] = "ON_NEXT_RESUME"; })(InstallMode = exports.InstallMode || (exports.InstallMode = {})); var SyncStatus; (function (SyncStatus) { /** * The application is up to date. */ SyncStatus[SyncStatus["UP_TO_DATE"] = "UP_TO_DATE"] = "UP_TO_DATE"; /** * An update is available, it has been downloaded, unzipped and copied to the deployment folder. * After the completion of the callback invoked with SyncStatus.UPDATE_INSTALLED, the application will be reloaded with the updated code and resources. */ SyncStatus[SyncStatus["UPDATE_INSTALLED"] = "UPDATE_INSTALLED"] = "UPDATE_INSTALLED"; /** * An optional update is available, but the user declined to install it. The update was not downloaded. */ SyncStatus[SyncStatus["UPDATE_IGNORED"] = "UPDATE_IGNORED"] = "UPDATE_IGNORED"; /** * An error happened during the sync operation. This might be an error while communicating with the server, downloading or unziping the update. * The console logs should contain more information about what happened. No update has been applied in this case. */ SyncStatus[SyncStatus["ERROR"] = "ERROR"] = "ERROR"; /** * There is an ongoing sync in progress, so this attempt to sync has been aborted. */ SyncStatus[SyncStatus["IN_PROGRESS"] = "IN_PROGRESS"] = "IN_PROGRESS"; /** * Intermediate status - the plugin is about to check for updates. */ SyncStatus[SyncStatus["CHECKING_FOR_UPDATE"] = "CHECKING_FOR_UPDATE"] = "CHECKING_FOR_UPDATE"; /** * Intermediate status - a user dialog is about to be displayed. This status will be reported only if user interaction is enabled. */ SyncStatus[SyncStatus["AWAITING_USER_ACTION"] = "AWAITING_USER_ACTION"] = "AWAITING_USER_ACTION"; /** * Intermediate status - the update package is about to be downloaded. */ SyncStatus[SyncStatus["DOWNLOADING_PACKAGE"] = "DOWNLOADING_PACKAGE"] = "DOWNLOADING_PACKAGE"; /** * Intermediate status - the update package is about to be installed. */ SyncStatus[SyncStatus["INSTALLING_UPDATE"] = "INSTALLING_UPDATE"] = "INSTALLING_UPDATE"; })(SyncStatus = exports.SyncStatus || (exports.SyncStatus = {})); var CodePush = /** @class */ (function () { function CodePush() { } CodePush.sync = function (options, syncCallback, downloadProgress) { var _this = this; if (!options || !options.deploymentKey) { throw new Error("Missing deploymentKey, pass it as part of the first parameter of the 'sync' function: { deploymentKey: 'your-key' }"); } if (CodePush.syncInProgress) { syncCallback && syncCallback(SyncStatus.IN_PROGRESS); return; } CodePush.syncInProgress = true; // by default, use our Cloud server options.serverUrl = options.serverUrl || "https://nativescript-codepush-server.herokuapp.com/"; CodePush.cleanPackagesIfNeeded(); CodePush.notifyApplicationReady(options.deploymentKey, options.serverUrl); syncCallback && syncCallback(SyncStatus.CHECKING_FOR_UPDATE); CodePush.checkForUpdate(options.deploymentKey, options.serverUrl).then(function (remotePackage) { if (!remotePackage) { syncCallback && syncCallback(SyncStatus.UP_TO_DATE); CodePush.syncInProgress = false; return; } if (options.ignoreFailedUpdates === undefined) { options.ignoreFailedUpdates = true; } var updateShouldBeIgnored = remotePackage.failedInstall && options.ignoreFailedUpdates; if (updateShouldBeIgnored) { console.log("An update is available, but it is being ignored due to having been previously rolled back."); syncCallback && syncCallback(SyncStatus.UP_TO_DATE); CodePush.syncInProgress = false; return; } var onError = function (error) { console.log("Download error: " + error); syncCallback && syncCallback(SyncStatus.ERROR); CodePush.syncInProgress = false; }; var onInstallSuccess = function () { appSettings.setString(CodePush.PENDING_HASH_KEY, remotePackage.packageHash); appSettings.setString(CodePush.CURRENT_HASH_KEY, remotePackage.packageHash); var onSuspend = function () { application.off("suspend", onSuspend); _this.killApp(false); }; syncCallback && syncCallback(SyncStatus.UPDATE_INSTALLED); var installMode = options.installMode || InstallMode.ON_NEXT_RESTART; var mandatoryInstallMode = options.mandatoryInstallMode || InstallMode.ON_NEXT_RESUME; switch (remotePackage.isMandatory ? mandatoryInstallMode : installMode) { case InstallMode.ON_NEXT_RESTART: console.log("Update is installed and will be run on the next app restart."); break; case InstallMode.ON_NEXT_RESUME: console.log("Update is installed and will be run when the app next resumes."); application.on("suspend", onSuspend); break; case InstallMode.IMMEDIATE: var updateDialogOptions = (options.updateDialog || {}); dialogs_1.confirm({ title: updateDialogOptions.updateTitle, message: (remotePackage.isMandatory ? updateDialogOptions.mandatoryUpdateMessage : updateDialogOptions.optionalUpdateMessage) + (updateDialogOptions.appendReleaseDescription ? "\n" + remotePackage.description : ""), okButtonText: updateDialogOptions.mandatoryContinueButtonLabel || "Restart", cancelButtonText: updateDialogOptions.optionalIgnoreButtonLabel || "Cancel", cancelable: true }).then(function (confirmed) { if (confirmed) { setTimeout(function () { return _this.killApp(true); }, 300); } else { // fall back to next suspend/resume instead application.on("suspend", onSuspend); } }); break; } CodePush.syncInProgress = false; }; var onDownloadSuccess = function (localPackage) { syncCallback && syncCallback(SyncStatus.INSTALLING_UPDATE); localPackage.install(onInstallSuccess, onError); }; syncCallback && syncCallback(SyncStatus.DOWNLOADING_PACKAGE); remotePackage.download(onDownloadSuccess, onError, downloadProgress); }, function (error) { console.log(error); CodePush.syncInProgress = false; if (syncCallback) { syncCallback(SyncStatus.ERROR); } }); }; CodePush.checkForUpdate = function (deploymentKey, serverUrl) { return new Promise(function (resolve, reject) { // by default, use our Cloud server serverUrl = serverUrl || "https://nativescript-codepush-server.herokuapp.com/"; var config = { serverUrl: serverUrl, appVersion: AppVersion.getVersionNameSync(), clientUniqueId: platform_1.device.uuid, deploymentKey: deploymentKey }; CodePush.getCurrentPackage(config) .then(function (queryPackage) { new TNSAcquisitionManager_1.TNSAcquisitionManager(deploymentKey, serverUrl).queryUpdateWithCurrentPackage(queryPackage, function (error, result) { if (error) { reject(error.message || error.toString()); } if (!result || result.updateAppVersion) { resolve(); return; } // At this point we know there's an update available for the current version var remotePackage = result; var tnsRemotePackage = new TNSRemotePackage_1.TNSRemotePackage(); tnsRemotePackage.description = remotePackage.description; tnsRemotePackage.label = remotePackage.label; tnsRemotePackage.appVersion = remotePackage.appVersion; tnsRemotePackage.isMandatory = remotePackage.isMandatory; tnsRemotePackage.packageHash = remotePackage.packageHash; tnsRemotePackage.packageSize = remotePackage.packageSize; tnsRemotePackage.downloadUrl = remotePackage.downloadUrl; // the server doesn't send back the deploymentKey tnsRemotePackage.deploymentKey = config.deploymentKey; // TODO (low prio) see https://github.com/Microsoft/cordova-plugin-code-push/blob/055d9e625d47d56e707d9624c9a14a37736516bb/www/codePush.ts#L182 // .. or https://github.com/Microsoft/react-native-code-push/blob/2cd2ef0ca2e27a95f84579603c2d222188bb9ce5/CodePush.js#L84 tnsRemotePackage.failedInstall = false; tnsRemotePackage.serverUrl = serverUrl; resolve(tnsRemotePackage); }); }) .catch(function (e) { return reject(e); }); }); }; CodePush.getCurrentPackage = function (config) { return new Promise(function (resolve, reject) { resolve({ appVersion: config.appVersion, deploymentKey: config.deploymentKey, packageHash: appSettings.getString(CodePush.CURRENT_HASH_KEY), isMandatory: false, failedInstall: false, description: undefined, label: undefined, packageSize: undefined, serverUrl: config.serverUrl }); }); }; CodePush.notifyApplicationReady = function (deploymentKey, serverUrl) { if (CodePush.isBinaryFirstRun()) { // first run of a binary from the AppStore CodePush.markBinaryAsFirstRun(); new TNSAcquisitionManager_1.TNSAcquisitionManager(deploymentKey, serverUrl).reportStatusDeploy(null, "DeploymentSucceeded"); } else if (!CodePush.hasPendingHash()) { var currentPackageHash = appSettings.getString(CodePush.CURRENT_HASH_KEY, null); if (currentPackageHash !== null && currentPackageHash !== CodePush.firstLaunchValue()) { // first run of an update from CodePush CodePush.markPackageAsFirstRun(currentPackageHash); var currentPackage = TNSLocalPackage_1.TNSLocalPackage.getCurrentPackage(); if (currentPackage !== null) { currentPackage.isFirstRun = true; new TNSAcquisitionManager_1.TNSAcquisitionManager(deploymentKey, serverUrl).reportStatusDeploy(currentPackage, "DeploymentSucceeded"); } } } }; CodePush.killApp = function (restartOnAndroid) { if (application.android) { if (restartOnAndroid) { //noinspection JSUnresolvedFunction,JSUnresolvedVariable var mStartActivity = new android.content.Intent(application.android.context, application.android.startActivity.getClass()); var mPendingIntentId = parseInt("" + (Math.random() * 100000), 10); //noinspection JSUnresolvedFunction,JSUnresolvedVariable var mPendingIntent = android.app.PendingIntent.getActivity(application.android.context, mPendingIntentId, mStartActivity, android.app.PendingIntent.FLAG_CANCEL_CURRENT); //noinspection JSUnresolvedFunction,JSUnresolvedVariable var mgr = application.android.context.getSystemService(android.content.Context.ALARM_SERVICE); //noinspection JSUnresolvedFunction,JSUnresolvedVariable mgr.set(android.app.AlarmManager.RTC, java.lang.System.currentTimeMillis() + 100, mPendingIntent); //noinspection JSUnresolvedFunction,JSUnresolvedVariable } android.os.Process.killProcess(android.os.Process.myPid()); } else if (application.ios) { exit(0); } }; CodePush.cleanPackagesIfNeeded = function () { var shouldClean = appSettings.getBoolean(CodePush.CLEAN_KEY, false); if (!shouldClean) { return; } appSettings.remove(CodePush.CLEAN_KEY); appSettings.remove(CodePush.BINARY_FIRST_RUN_KEY); TNSLocalPackage_1.TNSLocalPackage.clean(); }; CodePush.isBinaryFirstRun = function () { var firstRunFlagSet = appSettings.getBoolean(CodePush.BINARY_FIRST_RUN_KEY, false); return !firstRunFlagSet; }; /** * This key exists until a restart is done (removed by native upon start). * @returns {boolean} */ CodePush.hasPendingHash = function () { return appSettings.hasKey(CodePush.PENDING_HASH_KEY); }; CodePush.markBinaryAsFirstRun = function () { appSettings.setBoolean(CodePush.BINARY_FIRST_RUN_KEY, true); }; CodePush.firstLaunchValue = function () { return appSettings.getString(CodePush.UNCONFIRMED_INSTALL_KEY, null); }; CodePush.markPackageAsFirstRun = function (pack) { appSettings.setString(CodePush.UNCONFIRMED_INSTALL_KEY, pack); }; CodePush.CURRENT_HASH_KEY = "CODEPUSH_CURRENT_HASH"; // same as native CodePush.PENDING_HASH_KEY = "CODEPUSH_PENDING_HASH"; // same as native CodePush.CLEAN_KEY = "CODEPUSH_CLEAN"; // same as native (Android) CodePush.BINARY_FIRST_RUN_KEY = "BINARY_FIRST_RUN"; CodePush.UNCONFIRMED_INSTALL_KEY = "UNCONFIRMED_INSTALL"; CodePush.syncInProgress = false; return CodePush; }()); exports.CodePush = CodePush;