angular.module('ionic.service.deploy', ['ionic.service.core']) // Check after 5 seconds on initial load .constant('INITIAL_DELAY', 1 * 5 * 1000) // Watch every minute .constant('WATCH_INTERVAL', 1 * 60 * 1000) /** * @ngdoc service * @name $ionicDeploy * @module ionic.services.deploy * @description * * A simple way to push updates to your app. * * Initialize the service with your app id before calling other functions. * Then, use the check, download, extract and load functions to update and/or load * the updated version of your app. * * @usage * ```javascript * * $ionicDeploy.watch().then(function(){}, function(){}, function(hasUpdate) { * // called whenever there is a new version. * // Show a prompt to the user asking them to update or not * // If they choose to update, call $ionicDeploy.update(); * }); * * $ionicDeploy.unwatch() to stop watching for updates. * * * Full-manual mode to check/download/extract and update: * * // Check for updates * $ionicDeploy.check().then(function(response) { * // response will be true/false * if (response) { * // Download the updates * $ionicDeploy.download().then(function() { * // Extract the updates * $ionicDeploy.extract().then(function() { * // Load the updated version * $ionicTrack.load(); * }, function(error) { * // Error extracting * }, function(progress) { * // Do something with the zip extraction progress * $scope.extraction_progress = progress; * }); * }, function(error) { * // Error downloading the updates * }, function(progress) { * // Do something with the download progress * $scope.download_progress = progress; * }); * } * }, function(error) { * // Error checking for updates * }) * ``` */ .factory('$ionicDeploy', [ '$q', '$timeout', '$rootScope', '$ionicApp', '$ionicCoreSettings', 'WATCH_INTERVAL', 'INITIAL_DELAY', function ($q, $timeout, $rootScope, $ionicApp, $ionicCoreSettings, WATCH_INTERVAL, INITIAL_DELAY) { var get_ionic_app_id = function () { if ($ionicCoreSettings.get('app_id')) { return $ionicCoreSettings.get('app_id') } else if ($ionicApp.getApp().app_id) { return $ionicApp.getApp().app_id } else { return null; } }; var get_ionic_domain = function () { if ($ionicCoreSettings.get('domain')) { return $ionicCoreSettings.get('domain') } else if ($ionicApp.getApp().domain) { return $ionicApp.getApp().domain } else { return null; } }; return { channel_tag: 'production', /** * Watch constantly checks for updates, and triggers an * event when one is ready. */ watch: function (options) { var deferred = $q.defer(); var opts = angular.extend({ initialDelay: INITIAL_DELAY, interval: WATCH_INTERVAL }, options); function checkForUpdates() { this.check().then(function (hasUpdate) { if (hasUpdate) { $rootScope.$emit('$ionicDeploy:updateAvailable'); } // Notify deferred.notify(hasUpdate); }, function (err) { console.warn('$ionicDeploy: Unable to check for Ionic Deploy updates', err); }); // Check our timeout to make sure it wasn't cleared while we were waiting // for a server response if (this.checkTimeout) { this.checkTimeout = setTimeout(checkForUpdates.bind(this), opts.interval); } } // Check after an initial short deplay this.checkTimeout = setTimeout(checkForUpdates.bind(this), opts.initialDelay); return deferred.promise; }, /** * Stop watching for updates. */ unwatch: function () { clearTimeout(this.checkTimeout); this.checkTimeout = null; }, /** * Check the deploy server for new versions (if any) */ check: function () { var deferred = $q.defer(); if (typeof IonicDeploy != "undefined") { IonicDeploy.check(get_ionic_app_id(), this.channel_tag, get_ionic_domain(), function (result) { console.log("DEBUG DEPLOY: " + result); if (result && result === "true") { deferred.resolve(true); } else { deferred.resolve(false); } }, function (error) { deferred.reject(error); }); } else { deferred.reject("Plugin not loaded"); } return deferred.promise; }, /** * Download the new verison. * See update() below for a version that does this for you */ download: function () { var deferred = $q.defer(); if (typeof IonicDeploy != "undefined") { IonicDeploy.download(get_ionic_app_id(), function (result) { if (result !== 'true' && result !== 'false') { deferred.notify(result); } else { deferred.resolve(result === 'true'); } }, function (error) { deferred.reject(error); }); } else { deferred.reject("Plugin not loaded"); } return deferred.promise; }, /** * Extract the new version. * See update() below for a version that does this for you */ extract: function () { var deferred = $q.defer(); if (typeof IonicDeploy != "undefined") { IonicDeploy.extract(get_ionic_app_id(), function (result) { if (result !== 'done') { deferred.notify(result); } else { deferred.resolve(result); } }, function (error) { deferred.reject(error); }); } else { deferred.reject("Plugin not loaded"); } return deferred.promise; }, /** * Load the saved version of our app. */ load: function () { if (typeof IonicDeploy != "undefined") { IonicDeploy.redirect(get_ionic_app_id()); } }, /** * Initialize the app */ initialize: function (app_id) { if (typeof IonicDeploy != "undefined") { IonicDeploy.initialize(app_id); } }, /** * Set the deploy channel */ setChannel: function (channel_tag) { this.channel_tag = channel_tag; }, /** * Fetch info about the current deploy */ info: function () { var deferred = $q.defer(); if (typeof IonicDeploy != "undefined") { IonicDeploy.info(get_ionic_app_id(), function (result) { deferred.resolve(result); }, function (err) { deferred.reject(err); }); } else { deferred.reject("IonicDeploy plugin not loaded"); } return deferred.promise; }, /** * This is an all-in-one function that's meant to do all of the update steps * in one shot. * NB: I think that the way to handle progress is to divide the provided progress result * of each part by two (download and extract) and report that value. */ update: function () { var deferred = $q.defer(); if (typeof IonicDeploy != "undefined") { // Check for updates IonicDeploy.check(get_ionic_app_id(), this.channel_tag, get_ionic_domain(), function (result) { if (result === 'true') { // There are updates, download them var downloadProgress = 0; IonicDeploy.download(get_ionic_app_id(), get_ionic_domain(), function (result) { if (result !== 'true' && result !== 'false') { // Download is only half of the reported progress downloadProgress = (result / 2); deferred.notify(downloadProgress); } else { // Download complete, now extract console.log("Download complete"); IonicDeploy.extract(get_ionic_app_id(), function (result) { if (result !== 'done') { // Extract is only half of the reported progress var progress = downloadProgress + (result / 2); deferred.notify(progress); } else { console.log("Extract complete"); // Extraction complete, now redirect IonicDeploy.redirect(get_ionic_app_id()); } }, function (error) { // Error extracting updates deferred.reject(error); }); } }, function (error) { // Error downloading updates deferred.reject(error); }); } else { // There are no updates, redirect IonicDeploy.redirect(get_ionic_app_id()); } }, function (error) { // Error checking for updates deferred.reject(error); }); } else { deferred.reject("Plugin not loaded"); } return deferred.promise; } } }]) .run(['$ionicApp', '$ionicCoreSettings', function ($ionicApp, $ionicCoreSettings) { document.addEventListener("deviceready", onDeviceReady, false); var get_ionic_app_id = function () { if ($ionicCoreSettings.get('app_id')) { return $ionicCoreSettings.get('app_id') } else if ($ionicApp.getApp().app_id) { return $ionicApp.getApp().app_id } else { return null; } }; function onDeviceReady() { console.log("Ionic Deploy: Init"); if (typeof IonicDeploy != "undefined") { if (ionic.Platform.isAndroid()) { IonicDeploy.init(get_ionic_app_id(),get_ionic_app_id); } else { IonicDeploy.redirect(get_ionic_app_id()); } } }; }]);