IBM Support

Using MQ Telemetry Transport protocol in IBM Worklight mobile applications

Download


Abstract

This article describes how to use the MQ Telemetry Transport protocol (MQTT) in a hybrid mobile app, developed for the Android platform using IBM® Worklight Studio.

Download Description

This article describes how to use the MQ Telemetry Transport protocol (MQTT) in a hybrid mobile app, developed for the Android platform using IBM® Worklight Studio. It shows how to develop a simple Worklight app to send and receive messages and illustrates the key concepts involved in designing and developing such an app. It includes the source code for the app in order to illustrate these points and to help you develop your own apps. We assume a basic knowledge both of Worklight and MQTT.

Introduction:
The MQ Telemetry Transport (MQTT) protocol is a lightweight publish/subscribe messaging protocol, designed specifically for sending data over networks where connectivity is intermittent or bandwidth is at a premium. It provides a mechanism for phone or tablet apps to send data reliably without having to code retry logic in the app. Its efficient use of network and battery power, along with its integration with enterprise messaging middleware, makes it well-suited to use cases where an enterprise application needs to push data to one or more phone apps.

In this article we show how you can use Worklight Studio to develop a hybrid Android app that sends and receives messages using MQTT. The approach we use is to develop the app in HTML and JavaScript, and to use the Cordova (PhoneGap) libraries provided with Worklight to interface to native code that implements the MQTT protocol. This native code includes an Android Service that manages communications with MQTT when the app is not running in the foreground. We describe the function and design of the native code components, the JavaScript API that we use to provide access to them, and how to set up a Worklight Studio project to use them. We provide a file containing all the code required, along with a sample app.



The structure of the hybrid mobile app
The sample app - programming to MQTT in JavaScript
The Cordova plug-in
The Android Service
Importing the sample app into Worklight Studio
Developing your own mobile-enabled app using Worklight Studio


The structure of the hybrid mobile app
Figure 1 illustrates the structure of our mobile app - the pieces that make up our app (which we will describe in a minute) are shown as yellow boxes.

Figure 1. Structure of the hybrid app



We have developed our app as a Worklight hybrid app, with its user interface and all the application logic being coded using HTML, CSS and JavaScript. The Worklight Client API (shown in the blue box in the middle right of figure 1) lets the app’s JavaScript code use Android-specific UI controls and access device-specific hardware. Under the covers this Worklight API uses technology from the Apache open source Cordova project (formerly known as PhoneGap) to bridge from JavaScript to the native Java code needed to interface with the Android OS and device hardware. We have taken this approach and extended it to send and receive messages through MQTT. This way programmers can develop their application logic and user interface using regular JavaScript, while the detailed code to handle communications with the messaging service is implemented in native Java code. We provide a simple JavaScript API to separate the two pieces of code.

To handle the low-level details of the MQTT protocol we use the Java MQTT client from the Eclipse Paho project. This is a general-purpose Java library, and to adapt it for use in Android we have wrapped it in an Android Service, which will be described later in this article. One of the main benefits this approach provides is to allow incoming messages to be handled when the app itself is not running in the foreground. The Cordova plugin and JavaScript API components (shown in figure 1) serve as the interface between the Android Service and the JavaScript application logic. It is advisable to keep all application-specific logic in the JavaScript portion of the app, rather than in the Cordova plugin or Android Service, so that these components can be reused for other apps. The source code for the Java components is provided, so they can be adapted to your requirements.

In the following sections, we shall outline the components of the hybrid app.
The sample app – programming to MQTT in Javascript
The sample app demonstrates how to use MQTT, it is not intended to be a real end-user app. The app is similar to the Telemetry Client Utility that is shipped as part of MQ Explorer, and enables the user to exercise the functions of the MQTT protocol.

The app is based around the four main functions provided by MQTT:
  • Connecting to an MQTT server
  • Disconnecting from an MQTT server
  • Subscribing to receive messages from a Topic hosted by an MQTT server
  • Sending (publishing) messages to a Topic hosted by an MQTT server

It is made up of three pages, the first being the page that handles Connect and Disconnect (shown in Figure 2). A real-life application would not present all these options to the user – some would be hard coded, and others would be configured as application settings. A significant portion of the logic in the app is focused on the passing of these options across the UI. We hope that this UI code doesn’t obscure the essential simplicity of MQTT.

The Server, Port and Client Identifier parameters are required. The Server and Port give the coordinates of the MQTT server (Server can be a DNS name or IP address). This server could be implemented by the WebSphere MQ Telemetry feature, or an alternative such as the RSMB or a third party MQTT implementation. The remaining parameters are optional (see the MQTT protocol specification for details).

Figure 2. Connection Page




The app is coded as a Worklight hybrid app, so the page shown in figure 2 is implemented as an HTML form (in the file common/MQTTSample.html) and the logic of the app is coded as a collection of JavaScript functions, in the file common/js/MQTTSample.js. This article will illustrate some aspects of this logic by examining a few of the functions.

Listing 1 shows the function that reacts to the user pressing the app’s Connect button.

Listing 1. Code for the Connect button in Figure 2
function connect(form) {
   WL.Logger.debug("connect clicked");

   // Create a Messaging.Client object. This represents a connection to an MQTT server.
   try {
       client = new Messaging.Client(form.host.value, Number(form.port.value), form.clientId.value);

       // If the Client object has generated a new client id for us, then update the value shown in the UI
       if (form.clientId.value == "")
           form.clientId.value = client.clientId;
   } catch (exception) {
       WL.Logger.error("Exception creating client", exception);
       alert("Exception creating client");
   }

   // Set up Connection Options, using values from the connect form.
   var connectOptions = new Object();

   connectOptions.cleanSession = form.cleanSession.checked;
   connectOptions.keepAliveInterval = parseInt(form.keepAlive.value);

   if (form.userName.value && form.userName.value != "")
       connectOptions.userName = form.userName.value;
   if (form.password.value)
       connectOptions.password = form.password.value;

   // Add "Last Will and Testament" options, if a LWT message has been requested
   if (form.connectLWT.checked) {
       willMessage = new Messaging.Message(form.connectLWTMessage.value);
       willMessage.destinationName = form.connectLWTTopicName.value;
       willMessage.qos = parseInt(form.connectLWTQos.value);
       willMessage.retained = form.connectLWTRetained.checked;
       connectOptions.willMessage = willMessage;
   }

   // Set up callback functions to be notified when the connect call completes
   connectOptions.onSuccess = function() {
       connectForms();
       log("Connected - id is " + client.clientId);
   };
   connectOptions.onFailure = onDisconnect;

   // Set up the Client-wide callback handlers
   client.onConnectionLost = onDisconnect;
   client.onMessageArrived = onMessageArrived;
   client.onMessageDelivered = function(message) {
       log("Sent msg " + message.payloadString);
   };

   // Enable tracing of the API implementation
   client.trace = function(msg) {
       if (msg.severity == "debug")
           WL.Logger.debug(msg.message);
       else
           WL.Logger.error(msg.message);
   };

   // Now make the actual connection
   client.connect(connectOptions);
}
The first line uses the Worklight Logging API to log the fact that the Connect button has been clicked. The code then goes on to create a Messaging.Client object. In our Messaging API a Client object represents a connection between the app and an MQTT server (although at this stage, the app is not actually connected to its server). The hostname, port and MQTT client identifier are copied from the HTML form and passed as parameters to the Client constructor.

The MQTT client identifier is a string that uniquely identifies our client to the MQTT server. The MQ client identifier is used by the server to track state associated with the client, and an app that wants to “continue where it left off last time” needs to provide the same client identifier each time that it connects (elsewhere our app has code that saves the value that appears in the HTML form in local storage and restores it each time it starts up). If the user clears this value before pressing the Connect button, then the app will pass an empty string to the client constructor. If it receives an empty string, the API constructs a new random client identifier, and you can see we have code to update the UI with that new value in this case.

We then collect up the remaining input parameters from the HTML form and assemble them into a connect options object which will be used on the connect call itself.

An important point about Javascript programming is its asynchronous nature; a JavaScript app is in effect a collection of functions that react to events, such as the UI event we are looking at right now. Our Messaging API is itself asynchronous which means that calls, such as the connect call we are about to issue, don’t take effect immediately. There’s a good reason for this, Android applications are essentially single threaded and activities like setting up network connections can take several seconds to complete so we don’t want the whole User Interface to lock up while this happens. Now we do need to be able to tell whether our connect call has succeeded or not, so to do that the app provides a function to be called if and when it does. This function is passed to the connect function as the onSuccess connect option. In our case this function calls a second function (see listing 2) that enables/disables controls in the UI, such as the connect button itself. We also set up a function to be called back in the event that the connect call fails. In this case we are using a function (onDisconnect) that has been defined further on in the application.

As well as callbacks that are invoked when a specific API call completes, our API also has some client-wide callbacks:
  • The onConnectionLost callback is called if the API detects a loss of connection with the server that isn’t the direct result of a disconnect call. In our case we use the same onDisconnect method to handle this as is used for failure of the connect call.
  • The onMessageArrived callback enables the app to see incoming messages. We will come back to this later in this article.
  • The onMessageDelivered callback is called when the client has finished its work in sending the message (this is usually very shortly after the app has called send, but if there’s a problem with the network it could be some time later). In this app, we simply log the fact that it has been sent in our History window (the third page of the app).
  • The trace callback enables the API to emit internal trace information, which can be useful when debugging your own app. In listing 1 you can see how you can map this trace callback to the cross-platform logging service provided by the Worklight Client API.

The final step our function executes is to call the Client.connect method. It’s worth mentioning the asynchronous nature of Javascript Android programming again at this point. The connect operation will not begin until after our app’s function has returned, so if you were to include some extra lines of code after client.connect(connectOptions) the client will not be connected when you execute them. If you want to issue further calls to the messaging API, either put them in the onSuccess callback function or, as we have done, include them in other UI-called functions that are only called after onSuccess has been called. The approach used to achieve this is shown in Listing 2.

Listing 2. Enabling/Disabling UI operations, following a successful connect
function connectForms() {  
   
   form = document.getElementById('connect');
   form.host.disabled = "true";
   form.port.disabled = "true";
   form.clientId.disabled = "true";
   form.userName.disabled = "true";
   form.password.disabled = "true";
   form.cleanSession.disabled = "true";
   form.ssl.disabled = "true";
   form.keepAlive.disabled = "true";  
   
   form.connectLWTTopicName.disabled = "true";
   form.connectLWTMessage.disabled = "true";
   form.connectLWTQos.disabled = "true";
   form.connectLWTRetained.disabled = "true";
 
   form.conn.disabled = "true";
   form.disc.disabled = "";
   
   form = document.getElementById('sendReceive');
   form.subscribeTopicName.disabled = "";
   form.register.disabled = "";
   form.topicName.disabled = "";
   form.textMessage.disabled = "";
   form.sendButton.disabled = "";
}
This function, which is called by the onSuccess callback, disables the Connect button and the various connect option input fields, and enables the Send/Receive form. This takes us on to the second page of the app (shown in Figure 3) which provides users a way to send messages to an MQTT topic or to subscribe to receive them. At the bottom of the page it also displays the last message received (if any).

Figure 3. Sending and Receiving Messages

In Listing 3 we show the code that implements the Publish button. This introduces the second main construct in our API, the Message object.

Listing 3. Sending a message
function doSend(form) {
   WL.Logger.debug("send clicked");
   if (form.textMessage.value == "") {
       message = new Messaging.Message("");

   } else if (form.messageType && form.messageType.value === "HEX") {
       var hex = form.textMessage.value;        
       var buffer = new ArrayBuffer((hex.length)/2);
       var byteStream = new Uint8Array(buffer);
       var i = 0;  
       while (hex.length >= 2) {
           var x = parseInt(hex.substring(0, 2), 16);
           hex = hex.substring(2, hex.length);
           byteStream[i++] = x;
       }
       message = new Messaging.Message(buffer);
   } else
       message = new Messaging.Message(form.textMessage.value);

   message.destinationName = form.topicName.value;
   message.qos = parseInt(form.sendQos.value);  

   if (form.retained.checked)
       message.retained = true;
   client.send(message);

   // Save the topic name for the next time the app is run
   localStorage.topic = form.topicName.value;
}

The Message object can take a payload that is either a text string (and this could be a JavaScript object that has been serialized as a JSON string) or a binary object, which in JavaScript is represented using an ArrayBuffer. The Messaging.Message constructor accepts a parameter of either type, which it uses as the payload. We would imagine that most users of an app like this would be typing in text strings, but for completeness our UI allows users to type in message payloads in Hexadecimal notation, and the bulk of the code at the top of this listing shows you how you can take this Hex and convert it into an ArrayBuffer for passing in to the Message constructor. If the user has selected String input, then the String value is just passed in as it is.

The code then sets three further properties of the Message. Most important of these is the destinationName, which contains the name of the Topic that the message is to be published to. You can also set properties that determinte the Quality of Service to be used when sending the message, and a flag to say whether you want the MQTT server to retain the message for future new subscribers or not. Having done this, the client.send() call becomes simple; we could register callbacks to track success and failure of this call (as done with connect), but we haven’t done that here because we are already tracking successful message sends via the onMessageDelivered callback we saw in Listing 1. The last line of code in the listing 3 saves the topic name in the phone’s local storage, so that it can be accessed the next time the app is restarted.

By this stage, the code for the Subscribe button should hold few surprises.

Listing 4. Creating a subscription
function subscribe(form) {
   WL.Logger.debug("subscribe clicked");
   var topicFilter = form.subscribeTopicName.value;
   var options = {qos:Number(form.requestedQos.value),
       invocationContext:{filter: topicFilter},
       onSuccess:subscribeSucceeded,
       onFailure:subscribeFailed};

   try {
       client.subscribe(topicFilter, options);

   } catch (exception) {
       WL.Logger.error("Exception creating subscription", exception);
       alert("Subscribe to " + topicFilter + " failed");
   }
}

function subscribeSucceeded(result) {
   log ("Subscribed to " + result.invocationContext.filter);
   // Save topic for the next time the user runs the app
   localStorage.subTopic = result.invocationContext.filter;
}

function subscribeFailed(result) {
   log ("Subscribe to " + result.invocationContext.filter + " failed");
}
Listing 4 shows the code for Subscribe (the code for unsubscribe is very similar). The subscribe method in our API has two parameters: a topicFilter which can be a simple topic name or a wildcard topic expression as defined by MQTT (# being a wildcard expression that includes all topics), and an options parameter. The options parameter contains the usual callback attributes, along with a parameter that specifies the maximum quality of service we want used for this subscription.

The final page displays a history of events, including messages that are received by the app.

Figure 4. History page

The log() function that we have already seen used in several places, simply adds a record to this window. This is straightforward JavaScript code so we won’t comment on it further here. However it is worth showing the onMessageArrived callback, which you will recall was set on the client object back in Listing 2.

Listing 5. Processing an incoming message
function onMessageArrived(message) {
   WL.Logger.debug("message arrived");
   this.receivedMessage = message;
   displayMessage(message);
   log("Received " + message.payloadString);
}
As you can see in Listing 5, the callback is relatively unsophisticated. The callback is passed a Message object (the same as constructed in listing 4) and writes it to the window at the bottom of the send/receive page and also to the history window. The API provides a message.payloadBytes property which will return an ArrayBuffer containing the message payload, and that works whether the message is binary or String format. However if your app is dealing exclusively with String messages, then handling ArrayBuffers is inconvenient, so we also provide a message.payloadString property, as shown in Listing 5. This returns the payload of the message as a text String, but it can only do this in cases where the message actually is a valid (UTF8 encoded) string.


The Cordova Plug-in
The Cordova plug-in is made up of two parts: a JavaScript portion which you will find in the file android/js/mqttCordovaAndroidClient.js and a Java component that you can find in the com.ibm.mqtt.android.cordova.plugin.MQTTPlugin Java class. The JavaScript code implements the API outlined earlier in the article. It marshals up the parameters to be passed across to the Java code, and handles callbacks from the Java code, following the standard pattern for a Cordova plugin.

Listing 6. Cordova plugin actions
var PLUGIN_ACTION = {
   SEND_ACTION : "send",
   ACKNOWLEDGE_RECEIPT_ACTION : "acknowledgeReceipt",
   UNSUBSCRIBE_ACTION : "unsubscribe",
   SUBSCRIBE_ACTION : "subscribe",
   DISCONNECT_ACTION : "disconnect",
   CONNECT_ACTION : "connect",
   GET_CLIENT_ACTION : "getClient",
   START_SERVICE_ACTION : "startService",
   STOP_SERVICE_ACTION : "stopService",
   MESSAGE_ARRIVED_ACTION : "messageArrived",
   MESSAGE_DELIVERED_ACTION : "messageDelivered",
   ON_CONNECTION_LOST_ACTION : "onConnectionLost",
   TRACE_ACTION : "trace",
   SET_ON_CONNECT_CALLBACK : "setOnConnectCallbackId",
   SET_ON_CONNECTIONLOST_CALLBACK : "setOnConnectionLostCallbackId",
   SET_ON_MESSAGE_ARRIVED_CALLBACK : "setOnMessageArrivedCallbackId",
   SET_ON_MESSAGE_DELIVERED_CALLBACK : "setOnMessageDeliveredCallbackId",
   SET_TRACE_CALLBACK : "setTraceCallbackId",
   SET_TRACE_ENABLED : "setTraceEnabled",
   SET_TRACE_DISABLED : "setTraceDisabled"
};
The JavaScript portion communicates to the Java portion via a set of Actions (messages sent between Javascript and Java) as shown in Listing 6. The CONNECT, DISCONNECT, SUBSCRIBE, UNSUBSCRIBE and SEND Actions are sent from JavaScript to Java when the corresponding function in the JavaScript API is called by the application, and the ACKNOWLEDGE_RECEIPT Action is sent when the JavaScript app’s onMessageArrived callback has completed processing an incoming message.

As outlined in Listing 2 the Client object in the JavaScript API has four “unsolicited” callbacks (onMessageArrived, onMessageDelivered, onConnectionLost and trace) and there are four Actions that flow from JavaScript to Java corresponding to them. In order to register to receive these Actions, the Javascript calls cordova.exec with the special SET_XXX_CALLBACK Actions. Unlike our first set of Actions (CONNECT, DISCONNECT etc.) which can result in at most one asynchronous response, these special SET_XXX_CALLBACK Actions can receive many responses.

Listing 7. Executing a disconnect action
// call to the plugin to disconnect from the server
ClientImpl.prototype.disconnect = function(disconnectOptions) {
   var current_operation = "Client.disconnect";
   this._trace(current_operation);
   var context = this; // callbacks may run in another scope, so we need access to "this"

   var successCallback;
   if (disconnectOptions.onSuccess) {
       successCallback = disconnectOptions.onSuccess;
   } else {
       successCallback = function() {
           context._trace("disconnect - succeeded");
       };
   }

   var failureCallback;
   if (disconnectOptions.onFailure) {
       failureCallback = disconnectOptions.onFailure;
   } else {
       failureCallback = function(e) {
           context._trace("disconnect - failed : " + e);
       };
   }

   var invocationContext = disconnectOptions.invocationContext || {};

   if (!this.connected) {
       successCallback({
                       invocationContext : invocationContext
                       });
       return;
   }

   cordova.exec(successCallback, failureCallback, "MqttPlugin",
                PLUGIN_ACTION.DISCONNECT_ACTION, [ this.clientHandle,   invocationContext ]);

};
In Listing 7, we outline the code used to implement DISCONNECT, which sets up onSuccess and onFailure callback handlers and then calls cordova.exec to send the DISCONNECT action. This Action (like the other Actions) is asynchronous, so the cordova.exec call returns control immediately, and success or failure is then indicated by a subsequent call (via Cordova) to one of the callbacks. The START_SERVICE and STOP_SERVICE Actions, as their name suggests control the running of the Android Service (about which there’s more in the next section). START_SERVICE is called when the app connects.
The Android Service
The function of the Android Service is to take the Eclipse Paho MQTT client and adapt it to run in the Android environment. Our implementation is structured into several classes in the package com.ibm.mqtt.android.service
  • MqttService is the implementation of the Service itself. It extends the Android Service class.
  • MqttServiceClient contains the bulk of the logic that interfaces to the Paho client
  • MqttServiceConstants defines constants that are used by the Service (and also by the Cordova plugin when it interfaces to the service)
  • MessagingMessage is a Java implementation of the Messaging.Message object from the JavaScript API.
  • DatabaseMessageStore is a class that uses the Android SQLite database to hold a store of incoming messages that are en route to being delivered to the app
  • The remaining classes (MqttServiceBinder, MqttTraceHandler) are ancillary classes supporting the MQTTService class.

We won’t go in detail through the code, instead we will just mention a few of its more interesting features.

Firstly the Service implements an Android “Bound Service”. If we were to call the Paho MQTT client code directly from the Cordova plugin, then that code would run as part of the app’s Android Activity. An Android phone only has one Activity running at any one time, and when the user switches to a new app, or starts talking on the phone, the current Activity gets stopped and is placed on a stack while another Activity runs in its place. By placing the MQTT client in an Android service, we can ensure that it continues to run even when our app is stopped. Now you can see the reason for having the split between Cordova MQTT plugin (which is part of the Activity and therefore only runs when the app owns the phone’s UI) and the MqttService which can continue to run in the background. These two components communicate with each other using Android’s message passing mechanism (Android refers to these messages as Intents), and the asynchronous nature of this mechanism fits well with the asynchronous nature of the JavaScript API outined at the beginning of this article.



The main reason for wanting a Service running in the background is to be able to handle messages that arrive when the app’s Activity is stopped. The Service queues up these messages in the DatabaseMessageStore and notifies any Activities that it is associated with that it has a message for them. If and when an Activity restarts, its MQTT plugin will attempt to deliver these messages to the app.MqttService also includes a rudimentary interface to the Android Status notification service, to alert the user that there are messages waiting. This is shown in Listing 8, as you might wish to replace it with something more sophisticated.

Listing 8. The interface to the Android Notification service
void showNotification(String status) {
   traceDebug(TAG, "showNotification() new={" + status + "}");

   if (status == null) {
       notificationManager.cancel(NOTIFICATION_ID);
       return;
   }

   int iconId = getResources().getIdentifier("icon", "drawable", getPackageName());
   CharSequence tickerText = status;
   CharSequence contentTitle = "MqttService";
   CharSequence contentText = status;

   Intent notificationIntent = new Intent(this, MqttService.class);
   notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                        notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

   // the next two lines initialize the Notification, using the configurations above
   Notification notification = new Notification();
   notification.when = System.currentTimeMillis();
   notification.flags = Notification.FLAG_AUTO_CANCEL;

   notification.icon = iconId;
   notification.tickerText = tickerText;
   notification.setLatestEventInfo(getBaseContext(), contentTitle, contentText, contentIntent);
   notificationManager.notify(NOTIFICATION_ID, notification);
}
One other function that the Service provides is a degree of auto-reconnection. The service is notified when the phone goes in and out of network coverage, and attempts to re-establish the TCP/IP connection to the MQTT server when network coverage becomes available, without requiring involvement from the app itself (as the app Activity might not be running at the time). Note that this reconnection functionality is only applicable when cleanSession is set to false, as only then can we be confident that a reconnection will reestablish subscriptions and that the server will appropriately deal with messages sent during the hiatus in connection.
Importing the sample app into Worklight Studio
We have provided source code for the JavaScript app, the JavaScript API, the Android service and the Cordova Plug-in in a file called MQTTSample.zip that accompanies this article. For convenience we have also included the Eclipse Paho Java client for MQTT as object code. If you want to obtain the source code for this Java client, it can be downloaded from the Eclipse Paho web site, see http://www.eclipse.org/paho.

In this section we take you through the steps required to build and test the app using Worklight Studio.

Step 1. Create a new Worklight project and a Hybrid application in this project. You can do this by clicking on File/New.. and then selecting Worklight Project. This will bring up the panel shown in Figure 5.

Figure 5. Creating a new project

The project can be given any name you like, in this case we have chosen to call it MQTT. However in order to use the sample files we provide, you must give the app itself the name MQTTSample as shown in Figure 6.

Figure 6. Creating a new Hybrid app


Step 2. Create an Android environment by selecting the MQTTSample app in the project explorer. Right click on it and choose New Worklight Environment, This will bring up the panel shown in Figure 7 where you select Android phones and tablets and click on Finish.

Figure 7. Creating the Android environment


When you have done this, you should have created Worklight Studio’s default Android hybrid app.

Step 3. Unzip the files that you will find in the MQTTSample.zip into a directory of your choice, and import them into the Eclipse project, replacing some of the files in the default hybrid app. To do this, proceed as follows:

Firstly go the project Explorer and select the MQTTSample app that you have just created. Right click and choose Import from the drop-down menu. Choose General/File System as shown in Figure 7 and click Next.

Figure 8. Importing the code - part 1


On the next panel point to the directory or folder that contains the unzipped code and select its android and common subfolders as shown in Figure 8, and click Finish. Unless you have selected “Overwrite existing resources without warning” you will get prompted to overwrite the default hybrid app files with the ones that we have provided. You can either click Yes to All, or click Yes individually for each. For the record, the files that should be replaced are:
  • MQTTSample.html
  • MQTTSample.js
  • MQTTSample.css
  • AndroidManifest.xml
  • plugins.xml

This step will also import the Cordova plug-in, Android Service and the MQTT client, but since you won’t already have them in your project you shouldn’t get prompted for them.

Figure 9. Importing the code – part 2


You will now have the sample Android application ready to build in your Worklight project, in the normal way (select the Android environment and click on Run As /Build all and deploy to create a target Android project).
Developing your own MQTT-enabled apps using Worklight Studio
If you are developing a new app of your own, you might not wish to call it MQTTSample, but you might still want to use the Cordova plugin and Android service that we used in our MQTTSample app. To add them to your app, you may go straight to Step 3, but when importing the files (figure 9) select just the android folder. Be careful not to not overwrite the AndroidManifest.xml file (you may be prompted to do so) since the one we provide is for an app called MQTTSample. Also if you were to import it you might also overwrite other settings that you have made for your app. Similarly if you were to import plugins.xml you would lose any other Cordova plugins that you have added. Instead simply edit your existing versions of these files.

You need to add an additional line to the Android Manifest to tell it to load the MQTT Service. The line you need is shown in bold Listing 9. You also need to check that you Android app has the permissions needed to run the service. You will need the permissions shown in Listing 9, in addition to any others that are need by your application.

Listing 9. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8" ?>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

...
<application …>
...
<service android:name="com.ibm.mqtt.android.service.MqttService" />
</application>
...
</manifest>
You will need to edit the plugins.xml - located in: android/native/res/xml directory to register the MQTT plugin.

Listing 10 shows the plugins.xml that is contained in the MQTTSample.zip. This file includes all the default Cordova plugins specified by Worklight, along with the additional line that you need to use the MQTT plugin.

Listing 10. plugins.xml
<?xml version="1.0" encoding="utf-8"?>
<plugins>
<plugin name="App" value="org.apache.cordova.App"/>
<plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/>
<plugin name="Device" value="org.apache.cordova.Device"/>
<plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/>
<plugin name="Compass" value="org.apache.cordova.CompassListener"/>
<plugin name="Media" value="org.apache.cordova.AudioHandler"/>
<plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>
<plugin name="Contacts" value="org.apache.cordova.ContactManager"/>
<plugin name="File" value="org.apache.cordova.FileUtils"/>
<plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/>
<plugin name="Notification" value="org.apache.cordova.Notification"/>
<plugin name="Storage" value="org.apache.cordova.Storage"/>
<plugin name="Temperature" value="org.apache.cordova.TempListener"/>
<plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/>
<plugin name="Capture" value="org.apache.cordova.Capture"/>
<plugin name="Battery" value="org.apache.cordova.BatteryListener"/>
<plugin name="MqttPlugin" value="com.ibm.mqtt.android.cordova.plugin.MqttPlugin"/>
</plugins>

As well as adding this line to plugins.xml, you need to make sure that your app can see it, so as to be able to access the Javascript API that it implements. To do this you need to add the following line to your app’s HTML file.
<script type="text/javascript" src="js/mqttCordovaAndroidClient.js"></script>

Conclusion
We have demonstrated how a Hybrid mobile app that uses MQTT can be developed. To support this we have provided a sample app for Android platforms that can be used as the basis of user created apps, or as a simple test utility in its own right.

Acknowledgements
The design of the Android Service owes much to the inspiration of Dale Lane, and the Cordova plug-in to Bryce Curtis and Becky Gibson. We would like to thank Andy Banks for his work on the JavaScript API and for providing much of the JavaScript portion of our app. We also thank Simon McDonald for his help with Cordova.

Resources
Really Small Message Broker
MQTT protocol specification
Eclipse Paho project
IBM Worklight Developer Studio

Authors:
Peter Niblett ([email protected])
Mark Bluemel
Graham Hopkins

Prerequisites

IBM Worklight Studio with Android SDK.
An MQTT server which could be the WebSphere MQ Telemetry feature, or an alternative such as the RSMB or a third party MQTT implementation.

Installation Instructions

See above.

Off
[{"DNLabel":"WorklightSample.zip","DNDate":"04 Oct 2012","DNLang":"US English","DNSize":"677095","DNPlat":{"label":"Windows","code":"PF033"},"DNURL":"http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?popup=Y&li_formnum=L-SBRY-8Y9FGA&accepted_url=ftp://public.dhe.ibm.com/software/integration/support/supportpacs/individual/mqttsample.zip","DNURL_FTP":" ","DDURL":null}]

Technical Support

This article is provided in good faith and AS-IS. There is no warranty or further service implied or committed and any supplied sample code is not supported via IBM product service channels.

You may submit a question using the 'rate this page' below.

Please read the license information to determine if you want to use the download.

[{"Product":{"code":"SSFKSJ","label":"WebSphere MQ"},"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Component":"WMQ Telemetry","Platform":[{"code":"PF002","label":"AIX"},{"code":"PF016","label":"Linux"},{"code":"PF033","label":"Windows"}],"Version":"7.5;7.1","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}}]

Document Information

Modified date:
15 June 2018

UID

swg24033580