Customizing Direct Update

Overview

What is “Direct Update”? “Direct Update” is the direct delivery of updated web resources to deployed applications. Subject to the terms and conditions of the target platform, organizations are not required to upload new app versions to the app store or market. In IBM® MobileFirst Platform Foundation, this option is available for iPhone, iPad, Windows Phone 8, and Android apps.

In Worklight 6.1 and earlier, “Direct Update” was a part of init process. It wasn't customizable and could not be disabled.
Starting from Worklight 6.2 “Direct Update” became a security realm that can be customized and even disabled.

Basic Direct Update

In this blog I will describe how direct update can be customized.

So as I said earlier “Direct Update” is a security realm and it is defined like all security realms in autheticationConfig.xml file. It is enabled by default per client session on all supported platforms, including iPhone, iPad, Android, and Microsoft Windows Phone 8. Checks for Direct Update occur during requests to the server. If an update is available, the client displays a confirmation dialog. When the user accepts, the new resources are downloaded from the MobileFirst Server and the app restarts.

You can read about configuring “Direct Update” in authenticationConfig.xml in the Knowledge Center.

We start with new project and call it TestProject. Add a hybrid application TestApp and add a mobile environment of your choice (iPhone or Android). In this blog I will use Android. Add some code to main.css file so we can change it later to trigger direct update.
For example add background color to body:

1
2
3
body {
	background-color: blue;
}

Now we need to create some code in order to connect to Worklight server (unlike previous versions, Worklight application does not connect automatically as a part of init process). So lets add a button to index.html page:

1
<button onclick="WL.Client.setUserPref('somekey', 'somevalue');">Get Update</button>

Pressing that button will connect us to the server.

Now the application is ready. Lets test the basic direct update:

  1. Deploy the application to the server.
  2. Go to main.css file, change background color to red and save the changes.
  3. Re-deploy the application to the server.
  4. Restart the application on the client and press the "Get Update" button.

You should see "Direct Update Available" dialog. Press "Ok". Your application will be reloaded and the background color will be red.

Customizing Direct Update

Now that we have a basic application we can start customizing the way we deal with direct update.

We will use the handleDirectUpdate function of the direct update challenge handler to customize the direct update process and interface. The handleDirectUpdate function has the following format:

1
wl_directUpdateChallengeHandler.handleDirectUpdate = function (directUpdateData,directUpdateContext){...}

The function accepts the following arguments:

  • directUpdateData - a JSON object that contains the downloadSize property that represents the file's size in bytes of the update package to be downloaded from server.
  • directUpdateContext - a JavaScript object that exposes .start() and .stop() functions that start and stop the direct update flow.

Also we will use directUpdateCustomListener. The custom listener must implement the following methods:

1
2
3
4
5
6
7
8
var directUpdateCustomListener = {
  onStart: function(totalSize){
  },
  onProgress: function(status,totalSize,completedSize){
  },
  onFinish: function(status){
  }
};
The listener methods are called during the direct update process according to following rules:

  • onStart is called with the totalSize parameter that holds the size of the update file.
  • onProgress is called multiple times with status DOWNLOAD_IN_PROGRESStotalSize, and completedSize (the volume that is downloaded so far).
  • onProgress is called with status UNZIP_IN_PROGRESS.
  • onFinish is called with one of the final status codes (available here)

If you implement a custom direct update listener, you must ensure that the app is reloaded when the direct update process is complete and the onFinish() method has been called. You must also call wl_directUpdateChalengeHandler.submitFailure() if the direct update process fails to complete successfully.

Direct update in the background

Add an implementation of directUpdateCustomListener in main.js file right after wlCommonInit() function. Provide empty function implementations to the onStart and onProgress methods. Empty implementations cause the direct update process to run in the background.
To complete the direct update process, the application must be reloaded. The following options are available:

  • The onFinish method can be empty as well. In this case, direct update will apply after the application has restarted.
  • You can implement a custom dialog that informs or requires the user to restart the application.
  • The onFinish method can enforce a reload of the application by calling WL.Client.reloadApp().

I chose to inform user .
My listener looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
var directUpdateCustomListener = {
  onStart: function(totalSize){
  },
  onProgress: function(status,totalSize,completeSize){
  },
  onFinish: function(status){
    WL.SimpleDialog.show('New Update Available', 'Press reload button to update to new version',
      [{
        text : WL.ClientMessages.reload,
        handler : WL.Client.reloadApp
      }]);
  }
};

Add an implementation of the wl_directUpdateChallengeHandler.handleDirectUpdate function. Pass the directUpdateCustomListener implementation that you have created as a parameter to the function. Make sure directUpdateContext.start(directUpdateCustomListener) is called.
Here is my implementation of wl_directUpdateChallengeHandler.handleDirectUpdate (in main.js):

1
2
3
wl_directUpdateChallengeHandler.handleDirectUpdate = function(directUpdateData, directUpdateContext){
directUpdateContext.start(directUpdateCustomListener);
};

Run and deploy application to the server. Change background color. Save, run and deploy application to the server again. Restart application on the client, press “Get Update” button. Dialog appears saying “Press reload button to update to new version”. Press “Reload” on dialog and see how your background color has changed.

Direct update on demand

By default, the application checks for direct updates once per session. You can program the application to check for direct updates at a different point in time, for example, you can trigger a check for direct updates whenever a user clicks a button.
The mobile security test that is provided by default (in the authenticationConfig.xml file under the server/conf folder) contains a direct update security test. You need to disable this test if you want to trigger direct update on demand.
To disable the direct update security test, override it by adding mobilesecuritytest explicitly, omitting default direct update test behaviour. For example:

1
2
3
4
<mobilesecuritytest name="mobileTests">
  <testdeviceid provisioningType="none"></testdeviceid>
  <testuser realm="wl_anonymousUserRealm"></testuser>
</mobilesecuritytest>

Remove directUpdateCustomListener and wl_directUpdateChallengeHandler.handleDirectUpdate implementations from previous example. In index.html file change onclick action from WL.Client.setUserPref('somekey', 'somevalue'); to WL.Client.checkForDirectUpdate();. Actually WL.Client.checkForDirectUpdate(); calls for direct update. You can use it everywhere to ensure user runs a latest web resources.
Run and deploy your application to server. Open it. Change background color, run and deploy application to server again. Press “Get Update” button and see your background change.

Triggering direct update upon adapter call

Set your application to use a custom security test without direct update. The following example shows such a custom security test in the authenticationConfig.xml file:

1
2
3
4
<customsecuritytest name="customNoDirectUpdate">
  <test realm="wl_anonymousUserRealm" isInternalUserID="true" step="1"></test>
  <test realm="wl_deviceNoProvisioningRealm" isInternalDeviceID="true" step="2"></test>
</customsecuritytest>

Set your application to use that security test by adding it in to Android environment in application-descritor.xml file, like this:

Create a HTTP adapter, call it RSSReader and set it to use a custom security test with direct update defined.

1
<procedure name="getStories" securityTest="customWithDirectUpdateRequest"></procedure>[

The following example shows such a custom security test in the authenticationConfig.xml file:

1
2
3
4
5
<customsecuritytest name="customWithDirectUpdateRequest">
  <test realm="wl_directUpdateRealm" mode="perRequest"></test>
  <test realm="wl_anonymousUserRealm" isInternalUserID="true" step="1"></test>
  <test realm="wl_deviceNoProvisioningRealm" isInternalDeviceID="true" step="2"></test>
</customsecuritytest>

In index.html file change onclick action from WL.Client.checkForDirectUpdate(); to WL.Client.invokeProcedure({adapter : 'RSSReader', procedure : 'getStories'});
Build and deploy your adapter. Run and deploy your application. Change background color of your application, run and deploy it again.
Press button “Get Update” now RSSReader is invoked and because it is protected by Direct Update realm it will trigger direct update.

Handling direct update failure

Last but not least we're going to handle direct update failure.
Lets see how direct update failure can be handled, for example, failure caused by loss of connectivity. In this scenario, the user is prevented from using the app even in offline mode. A dialog is displayed offering the user the option to try again.
Create a global variable to store the direct update context so that you can use it subsequently when the direct update process fails. For example (in main.js file):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var savedDirectUpdateContext;
//Implement a direct update challenge handler. Save the direct update context here. For example:

wl_directUpdateChallengeHandler.handleDirectUpdate = function(directUpdateData, directUpdateContext){
  savedDirectUpdateContext = directUpdateContext; // save direct update context
  var downloadSizeInMB = (directUpdateData.downloadSize / 1048576).toFixed(1).replace(".", WL.App.getDecimalSeparator());
  var directUpdateMsg = WL.Utils.formatString(WL.ClientMessages.directUpdateNotificationMessage, downloadSizeInMB);
  WL.SimpleDialog.show(WL.ClientMessages.directUpdateNotificationTitle, directUpdateMsg, [{
    text : WL.ClientMessages.update,
    handler : function() {
      directUpdateContext.start(directUpdateCustomListener);
    }
  }]);
};

Create a function that starts the direct update process by using the direct update context. For example:

1
2
3
restartDirectUpdate = function () {
  savedDirectUpdateContext.start(directUpdateCustomListener); // use saved direct update context to restart direct update<br />
};

Implement directUpdateCustomListener. Add status checking in the onFinish method. If the status starts with "FAILURE", open a modal-only dialog with the option "Try Again". For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var directUpdateCustomListener = {
onStart : function(totalSize) {
		alert('onStart: totalSize = ' + totalSize + 'Byte');
	},
	onProgress : function(status, totalSize, completeSize) {
		alert('onProgress: status = ' + status + ' completeSize = '
				+ completeSize + 'Byte');
	},
	onFinish : function(status) {
		alert('onFinish: status = ' + status);
		var pos = status.indexOf("FAILURE");
		if (pos > -1) {
			WL.SimpleDialog.show('Update Failed', 'Direct Update failed. Please retry.', [ {
				text : "Try Again",
				handler : restartDirectUpdate
			// restart direct update
			} ]);
		}
		var posSuccess = status.indexOf("SUCCESS");
		if (posSuccess > -1) {
			WL.Client.reloadApp();
		}
	}
};

Run and deploy application to the server. Change background color. Save, run and deploy application again. Restart application on the client, press the “Get Update” button.
In order to simulate network failure, stop MobileFirst server when you get “Update is available” dialog.
After a while the application recognizes that there is a network problem and a dialog appears. Press “Ok” and you will get “Update Failed” dialog. Start MobileFirst server to simulate “network is back” and press “Try again”. Direct update is restarted.

For more information please visit Configuring and customizing direct update.

Last modified on May 01, 2016
Share this post: