Skip to content

MQTT failure on Android #530

@geoff0522

Description

@geoff0522

I've been developing some apps with MQTT communications and have encountered a problem on Android with the Paho library. I had a couple of apps that were functioning fine until the latest update to the "io.github.mayzs:paho.mqtt.android:1.2.3" library. I use Android Studio for development and, when I updated to this version from version 1.2.1, Mqtt stopped communication. When I connect, the IMqttActionListener does not get called on either the onSuccess or the onFailure methods, although the client seems to be connected. Further, I am able to subscribe and publish but no messages ever arrive at the callback. Published messages do get to the target client and, although the target client is working and replies, nothing arrives at the Android device. If I simply downgrade the version to 1.2.1, everything works correctly.

Here is a program I used to test this.

This is the build gradel.

plugins {
    alias(libs.plugins.android.application)
}

android {
    namespace = "com.gelbintergalactic.mqtttest"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.gelbintergalactic.mqtttest"
        minSdk = 35
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
}

dependencies {
    implementation(libs.lifecycle.service)
    implementation(libs.work.runtime)
    implementation(libs.appcompat)
    implementation(libs.material)
    implementation(libs.activity)
    implementation(libs.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
    implementation(libs.org.eclipse.paho.client.mqttv3)
    implementation("io.github.mayzs:paho.mqtt.android:1.2.1")
}

Here is the Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MqttTest">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name="org.eclipse.paho.android.service.MqttService"/>
    </application>

</manifest>

Here is the MainActivity

package com.gelbintergalactic.mqtttest;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    MqttAndroidClient mqttClient;
    String broker = "tcp://test.mosquitto.org";
    boolean brokerDisconnected = true;
    String deviceID = "RainTotals";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        mqttConnect(this, broker);


        Runnable runnable = () -> {
            do {
                // Get yearly and seasonal totals
                try {
                    if (mqttClient != null && mqttClient.isConnected()) {
                        byte[] payload = {0};
                        payload = deviceID.getBytes(StandardCharsets.UTF_8);
                        mqttClient.publish("RainGauge0\\sendData", payload, 0, false);
                    }
                }
                catch(MqttException e){
                        String errorMsg = e.getLocalizedMessage();
                    }
                catch(Exception ignored){

                    }
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    String errorMsg = e.getLocalizedMessage();
                }
                if( !mqttClient.isConnected() ){
                    mqttConnect(getBaseContext(), broker); // Reconnect
                }
            } while (true);
        };
        new Thread(runnable).start();
    }

    private boolean mqttConnect(Context context, String brokeraddr) {
        String clientID = MqttClient.generateClientId();
        mqttClient = new MqttAndroidClient(context, brokeraddr, clientID);
        MqttConnectOptions opts = new MqttConnectOptions();
        //opts.setConnectionTimeout(30);
        //opts.setAutomaticReconnect(true);
        opts.setKeepAliveInterval(20);
        try {
            mqttClient.connect( opts, context, new IMqttActionListener() {

                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    brokerDisconnected = false;
                    mqttSetReceiveListener();
                    mqttSubscribe("yearly", 0);
                    byte[] payload = {0};
                    String deviceID = "RainTotals";
                    payload = deviceID.getBytes(StandardCharsets.UTF_8);
                    try {
                        mqttClient.publish("RainGauge0\\sendData", payload, 0, false );
                    } catch (MqttException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    brokerDisconnected = true;
                }
            });
            return !brokerDisconnected; // Successful connection
        } catch (MqttException e) {
            return false; // Connection failure
        }
        catch (Exception e){
            return false;
        }
    }

    private boolean mqttSubscribe( String topic, int qos ) {
        String topicString = String.format(Locale.getDefault(), "RainTotals\\%s",  topic);
        try{
            mqttClient.subscribe(topicString, qos);
            return true;
        }
        catch( MqttException e ) {
            return false;
        }
        catch( Exception e ){
            Log.e("mqtt", e.getMessage());
            return false;
        }
    }

    private void mqttSetReceiveListener(){
        mqttClient.setCallback(
                new MqttCallback() {
                    @Override
                    public void connectionLost(Throwable cause) {
                        return;
                    }

                    @Override
                    public void messageArrived(String topic, MqttMessage message) throws Exception {
                        try {
                            if( topic.contains("yearly")){
                                String msg = new String(message.getPayload());
                                String x = msg;
                            }
                        }
                        catch(Exception e){
                        }
                    }

                    @Override
                    public void deliveryComplete(IMqttDeliveryToken token) {
                    }
                }
        );
    }
}

I run Android Studio on a Windows 11 computer and run the app on a Google Pixel 8 pro. I use the test.mosquito.org Mqtt broker and this app communicates with a Windows app using M2Mqtt. Thanks for listening.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions