appupdate.js

1       // ${project.version}
2       var exec = require('cordova/exec'),
3           channel = require('cordova/channel'),
4           logonFired = false, // Flag to determine if logon manager is done
5           promptActive = false, // Flag to prevent prompt from displaying more than once
6           bundle = null; // Internationalization. Loaded with device ready
7       
8       
9       // Event channels for AppUpdate
10      var channels = {
11          'checking': channel.create('checking'),
12          'noupdate': channel.create('noupdate'),
13          'downloading': channel.create('downloading'),
14          'error': channel.create('error'),
15          'updateready': channel.create('updateready')
16      };
17      
18      // Holds the dom 0 handlers that are registered for the channels
19      var domZeroHandlers = {};
20      
21      // Private callback that plugin calls for events
22      var _eventHandler = function (event) {
23          if (event.type) {
24              if (event.type in channels) {
25                  channels[event.type].fire(event);
26              }
27          }
28      };
29      
30      /** @namespace sap */
31      
32      /**
33       * Used to provide server-based updates to the application content.
34       * <br/><br/>
35       * The AppUpdate plugin updates the contents of the www folder of deployed Kapsel
36       * applications.  After an application successfully does a logon to an SAP Mobile Platform 3
37       * server, the AppUpdate plugin is able to download an available update. See Uploading Hybrid Apps in user documentation
38       * for information on how to upload an update to SAP Mobile Platform 3 server.
39       * <br/><br/>
40       * After an update is completely downloaded, the application user is 
41       * prompted to install the update and restart the application.  They can decline
42       * if they wish.
43       * <br/><br/>
44       * Once an update is installed, the application's revision number is updated.
45       * <br/><br/>
46       * <b>Adding and Removing the AppUpdate Plugin</b><br/>
47       * The AppUpdate plugin is added and removed using the
48       * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>.<br/>
49       * <br/>
50       * To add the AppUpdate plugin to your project, use the following command:<br/>
51       * cordova plugin add <path to directory containing Kapsel plugins>\appupdate<br/>
52       * <br/>
53       * To remove the AppUpdate plugin from your project, use the following command:<br/>
54       * cordova plugin rm com.sap.mp.cordova.plugins.appupdate
55       * <br/><br/>
56       * 
57       * <b>Hybrid App Revision Preference</b><br/>
58       * This is an optional preference that tells the AppUpdate plugin if the local 
59       * assets are uploaded to the server, and at what number.  If this preference is 
60       * not provided, the default revision is 0.
61       * In your config.xml file you can add the following preference:<br/>
62       * <preference name="hybridapprevision" value="1" />
63      <br/>
64      <br/>
65       * This means that the local assets in your www folder are uploaded to the server 
66       * and the server is reporting revision 1 for them.  This allows the application 
67       * to receive a delta update when revision 2 is available, instead of a full update.
68       * <br/><br/>
69       *
70       * <b>Caveats</b><br/>
71       * It is important to test that your update has valid HTML, JavaScript, and CSS.  
72       * Otherwise, the update could prevent the application from functioning correctly, 
73       * and may no longer be updateable.  You can test the updated application in a 
74       * separate simulator or other test device.  You can also validate your 
75       * JavaScript with tools like <a href="http://www.jslint.com">JSLint</a>, or 
76       * <a href="http://www.jshint.com">JSHint</a>.  
77       * You can validate CSS with <a href="http://csslint.net">CSS Lint</a>.
78       * <br/><br/>
79       * 
80       * @namespace
81       * @alias AppUpdate
82       * @memberof sap
83       */
84      module.exports = {
85          /**
86           * Force an update check.  By default, updates occur automatically during logon and resume.
87           * See events for what is fired during this process. 
88           * @example
89           * sap.AppUpdate.update();
90           */
91          update: function () {
92              // Abort if logon event has not yet fired
93              if (logonFired) {
94                  sap.Logon.unlock(function (connectionInfo) {
95                      //Add application ID required for REST call
96                      connectionInfo.applicationId = sap.Logon.applicationId;
97      
98                      exec(_eventHandler, null, 'AppUpdate', 'update', [connectionInfo]);
99                  });
100             }
101         },
102     
103         /**
104          * Replaces the app resources with any newly downloaded resources.
105          * @example
106          * sap.AppUpdate.reloadApp();
107          */
108         reloadApp: function () {
109             exec(null, null, 'AppUpdate', 'reloadApp', []);
110         },
111     
112         /**
113          * Removes all local updates and loads the original Web assets bundled with the app. Call this after deleteRegistration.
114          * Reset calls error callback if it is called during the update process.
115          * @example
116          * sap.Logon.core.deleteRegistration(function() { 
117          *     sap.AppUpdate.reset();
118          * }, function() {});
119          */
120         reset: function (successCallback, errorCallback) {
121             exec(successCallback, errorCallback, 'AppUpdate', 'reset', []);
122         },
123     
124         /**
125          * Add a listener for an AppUpdate event.  See events for available event names.
126          * @param {string} eventname Name of the app update event.
127          * @param {function} f Function to call when event is fired.
128          * @example
129          * sap.AppUpdate.addEventListener('checking', function(e) {
130          *     console.log("Checking for update");
131          * });
132          */
133         addEventListener: function (eventname, f) {
134             if (eventname in channels) {
135                 channels[eventname].subscribe(f);
136             }
137         },
138     
139         /**
140          * Removes a listener for an AppUpdate event.  See events for available event names.
141          * @param {string} eventname Name of the app update event.
142          * @param {function} f Function that was registered.
143          * @example
144          * // Adding the listener
145          * var listener = function(e) {
146          *     console.log("Checking for update");
147          * });
148          * sap.AppUpdate.addEventListener('checking', listener);
149          *
150          * // Removing the listener
151          * sap.AppUpdate.removeEventListener('checking', listener);
152          */
153         removeEventListener: function (eventname, f) {
154             if (eventname in channels) {
155                 channels[eventname].unsubscribe(f);
156             }
157         }
158     
159         /**
160          * Event fired when AppUpdate is checking for an update.
161          *
162          * @event sap.AppUpdate#checking
163          * @type {object}
164          * @property {string} type - The name of the event.  Value is 'checking.' 
165          * @example
166          * sap.AppUpdate.addEventListener('checking', function(e) {
167          *     console.log("Checking for update");
168          * });
169          */
170     
171         /**
172          * Event fired when AppUpdate finds no available updates on the server.
173          *
174          * @event sap.AppUpdate#noupdate
175          * @type {object}
176          * @property {string} type - The name of the event.  Value is 'noupdate.' 
177          * @example
178          * sap.AppUpdate.addEventListener('noupdate', function(e) {
179          *     console.log("No update");
180          * });
181          */
182     
183         /**
184          * Event fired when AppUpdate has found an update and is starting the download.
185          *
186          * @event sap.AppUpdate#downloading
187          * @type {object}
188          * @property {string} type - The name of the event.  Value is 'downloading.' 
189          * @example
190          * sap.AppUpdate.addEventListener('downloading', function(e) {
191          *     console.log("Downloading update");
192          * });
193          */
194     
195         /**
196          * Event fired when AppUpdate encounters an error while checking for an update or while downloading an update.
197          * The status code and status message are provided with this event.
198          *
199          * @event sap.AppUpdate#error
200          * @type {object}
201          * @property {string} type - The name of the event.  Value is 'error.' 
202          * @property {int} statusCode - The HTTP error code.
203          * @property {string} statusMessage - The HTTP status message.     
204          * @example
205          * sap.AppUpdate.addEventListener('error', function(e) {
206          *     console.log("Error downloading update. statusCode: " + e.statusCode + " statusMessage: " + e.statusMessage);
207          * });
208          */
209     
210         /**
211          * Event fired when AppUpdate has a newly downloaded update available.  
212          * A default handler is already added to sap.AppUpdate.onupdateready that will ask the user to reload the app.
213          * When using this event, you should call sap.AppUpdate.reloadApp() to apply the downloaded update.
214          *
215          * @event sap.AppUpdate#updateready
216          * @type {object}
217          * @property {string} type - The name of the event.  Value is 'updateready.'
218          * @property {int} revision - The revision that was downloaded.
219          * @example
220          *
221          * // This listens for updateready event.  
222          * // Note: Use sap.AppUpdate.onupdateready if you want to override the default handler.
223          * sap.AppUpdate.addEventListener('updateready', function(e) {
224          *     console.log("Update ready");
225          * });
226          *
227          * // Override the default handler so that the update is automatically loaded, 
228          * // without first prompting the user for permission.
229          * sap.AppUpdate.onupdateready = function(e) {
230          *     // No notification just reload
231          *     console.log("Apply application update...");
232          *     sap.AppUpdate.reloadApp();
233          * };
234          *
235          * // Override the default handler with a custom prompt to notify the user that the 
236          * // application is ready to update.
237          * sap.AppUpdate.onupdateready = function() {
238          *     console.log("Confirming application update…");
239          *     navigator.notification.confirm('Update Available',
240          *        function(buttonIndex) {
241          *            if (buttonIndex === 2) {
242          *                console.log("Applying application update…");
243          *                sap.AppUpdate.reloadApp();
244          *            }
245          *        }, 
246          *        "Update", ["Later", "Relaunch Now"]);
247          * };
248          */
249     };
250     
251     // Add getter/setter for DOM0 style events
252     for (var type in channels) {
253         function defineSetGet(eventType) {
254             module.exports.__defineGetter__("on" + eventType, function () {
255                 return domZeroHandlers[eventType];
256             });
257     
258             module.exports.__defineSetter__("on" + eventType, function (val) {
259                 // Remove current handler
260                 if (domZeroHandlers[eventType]) {
261                     module.exports.removeEventListener(eventType, domZeroHandlers[eventType]);
262                 }
263     
264                 // Add new handler
265                 if (val) {
266                     domZeroHandlers[eventType] = val;
267                     module.exports.addEventListener(eventType, domZeroHandlers[eventType]);
268                 }
269             });
270         }
271     
272         defineSetGet(type);
273     }
274     
275     // Add default update ready implementation
276     module.exports.onupdateready = function () {
277         if (!promptActive) {
278             promptActive = true;
279     
280             var onConfirm = function (buttonIndex) {
281                 promptActive = false;
282                 if (buttonIndex === 2) {
283                     // Only reload if we are unlocked
284                     sap.Logon.unlock(function (connectionInfo) {
285                         //Add application ID required for REST call
286                         connectionInfo.applicationId = sap.Logon.applicationId;
287     
288                         module.exports.reloadApp();
289                     });
290                 }
291             }
292     
293             if (!bundle) {
294                 // Load required translations.
295                 var i18n = require('com.sap.mp.cordova.plugins.i18n.i18n');
296                 bundle = i18n.load({
297                     path: "plugins/com.sap.mp.cordova.plugins.appupdate/www"
298                 });
299             }
300     
301             window.navigator.notification.confirm(
302                 bundle.get("update_available"),
303                 onConfirm,
304                 bundle.get("update"), [bundle.get("later"), bundle.get("relaunch_now")]);
305         }
306     }
307     
308     // When logon is ready, an update check is started.
309     document.addEventListener("onSapLogonSuccess", function () {
310         logonFired = true;
311         module.exports.update();
312     }, false);
313     
314     document.addEventListener("onSapResumeSuccess", module.exports.update, false);