This is the sixth part in a series of blog posts looking at integrating Zebra Android devices as IoT clients in a public cloud infrastructure.  For other posts in this series, please see the links below:


This post expands on the concepts already discussed in Part 5 – Microsoft Azure IoT Hub Data Processing


In part 5 of this post series, we covered simulating an MQTT message to the Azure IoT Hub using a small C# application and in this post we will replace that test client with an MQTT client on a real device. To achieve this I will take inspiration from the official Azure IoT Sample for Java, specifically the Android device sample.  Full credit to the original authors.


Connection information

In part 5 of this post series, we created a test-device in the Azure IoT Hub named ‘test-device’ as part of the setup script.  To keep things simple, we will reuse that same test device which will now represent our physical Zebra Android device.  Although the simulator used the primary key to connect, our physical device will use the ‘connection string’ so be aware of that change.


We need the following connection information:


Setting Description
Connection String

Defines all the attributes required to connect the IoT device to Azure.  The string will be in the format “;DeviceId=XXXXXX;SharedAccessKey=XXXXXXXXXXX”.

This tutorial will use the HostName, ‘EntAndroidHub’ and the DeviceId, ‘test-device'.

You can find the connection string from the Azure portal, click on resources group, select the appropriate resource group, click the ‘IoT Hub’, Select ‘IoT Devices’, Click the device (e.g. test-device) and you should see the connection string as one of the device attributes.


The sample app

I have put together a sample client which can be used to connect to supported cloud IoT solutions and send both dummy and real data.  Please clone the client app from GitHub and run it on a device, being sure to grant any requested runtime permissions.


To use the Azure device client, add the following to your gradle file:

implementation (''){
exclude module:


I notice the sample app also adds some packagingOptions in the app.gradle which I needed to also copy in my sample app to get it to run.


Testing the connection

If you have not already done so, clone the client app from GitHub and run it on a device, you should see something similar to the below:



Either modify the connection setting to match your own or modify the file to change the default setting.  I strongly recommend updating the java file and rebuilding.


Use the ‘Connect’, ‘Disconnect’ and ‘Test’ buttons and the status message at the top of the UI should update to show whether the connection succeeded.


Test: Client connected Test: Client disconnected
try {

    client = new DeviceClient(connectionString, IotHubClientProtocol.MQTT);

} catch (URISyntaxException e) {


    return false;




    connected = true;


catch (IOException e)


    lastConnectionError = e.getMessage();

    connected = false;

    try {


    } catch (IOException e1) {



    return false;


return true;

Sending dummy data

After connecting to Azure and observing a successful connection status message, tap the ‘Send Data’ tab.  From this tab enable the “Send Dummy Data” switch and you should see something like the below

Scroll down to the bottom of the view and click the “Send Dummy Data” button, you should see an indication that the data was successfully sent.

This is publishing a message using the Azure device client.  To make the server processing easier, we make the determination on the client whether the battery level is critical or not and add a separate property to the message to indicate as much:

long dt = System.currentTimeMillis();

DateFormat formatter = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss");

String dateTime = formatter.format(dt);

JSONObject msgPayload = new JSONObject();

try {

    msgPayload.put("deviceId", deviceId);

    msgPayload.put("dateTime", dateTime);

    msgPayload.put("model", model);

    msgPayload.put("lat", lat);

    msgPayload.put("lng", lng);

    msgPayload.put("battLevel", battLevel);

    msgPayload.put("battHealth", battHealth);

    msgPayload.put("osVersion", osVersion);

    msgPayload.put("patchLevel", patchLevel);

    msgPayload.put("releaseVersion", releaseVersion);

} catch (JSONException e) {


    return false;


Message message = new Message(msgPayload.toString().getBytes());


    message.setProperty("batteryLevel", "critical");


    message.setProperty("batteryLevel", "normal");


EventCallback eventCallback = new EventCallback();

client.sendEventAsync(message, eventCallback, 1);

Sending real data

To send real data, select the ‘Azure’ radio button from the ‘Connect’ tab after disconnecting from the test connection.  In the ‘Send Data’ pane, slide the ‘Send Real Data’ toggle to on.


A WorkManager has now been started which will send device data in the background about every 15 minutes, though this frequency will be impacted by the device going into doze so you may not see messages this frequently.


The code to create the periodic request is given below, every roughly 15 minutes the worker is will connect to the cloud IoT service, publish the real device data and then disconnect from the cloud IoT service.  Because the worker needs to connect, we pass the required connection information.

PeriodicWorkRequest.Builder sendRealDataBuilder =

        new PeriodicWorkRequest.Builder(SendRealDataWorker.class,

                PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);

//  Pass the MQTT connection information to the worker.  The long-term worker is responsible for

//  making and breaking the MQTT connection when needed.

Data metaData = new Data.Builder().putInt(MQTT_SERVER_ENDPOINT, radioGroup.getCheckedRadioButtonId())

        .putString(MQTT_DEVICE_ID, txtDeviceId.getText().toString())    //  Common

        .putString(MQTT_CONNECTION_STRING, txtConnectionString.getText().toString()) //  Azure


PeriodicWorkRequest sendRealDataWork = sendRealDataBuilder.



sendRealDataWorkId = sendRealDataWork.getId();

The actual work that gets performed every roughly 15 minutes is defined in the doWork() function of the SendRealDataWorker class.

The following data is sent periodically:

If you followed the cloud configuration as described in part 5, you will see real device data being displayed in Power BI from which you can make informative dashboards and will start receiving emails if your device battery goes below 15%:


Power BI dashboard for connected Android device(s)



That concludes this post series comparing connecting to an Android device with GCP, AWS and Azure and the obvious question is 'which is the best?'.  Frankly, I am not qualified to deliver an authoritative general answer to that question but in terms of connecting with an Android device and processing data from an IoT endpoint, all the cloud solutions are equally capable and the choice will either come down to personal / business preferences or some aspect of the cloud solution unrelated to IoT.


All the providers were able to do what I would consider a minimum viable product for a solution which treats an Android device as an IoT endpoint:

  • MQTT support for low power, bidirectional connections
  • Script support for automatic provisioning
  • Identity management and secure device connections
  • Flexible data processing within the cloud solution
  • Extensive tutorials and help

So, I would personally be happy recommending any of the big cloud providers for this purpose.