Android集成MQTT教程:实现高效通信和实时消息传输

MQTT是一种基于发布/订阅模式的消息传输协议,它使用TCP/IP协议进行通信。MQTT的设计原则是轻量级、简单和可靠,适用于各种网络环境和设备。MQTT采用了订阅(Subscribe)和发布(Publish)的模式,客户端可以订阅感兴趣的主题(Topic),同时也可以发布消息到指定的主题。

接入:
一:添加MQTT依赖库 在Android项目的build.gradle文件中添加MQTT依赖库的引用,例如:复制

implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation('org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0')

2:添加申请权限




 
  
 
  

3:创建Mqttservice继承自service

/**
 * date:2023/8/16
 * author:wangsimin
 * funcation:mqtt协议
 */
public class MqttService extends Service {

    public static final String TAG = "MqttService";

    private static MqttAndroidClient client;
    private MqttConnectOptions conOpt;
    private String serverURI = "tcp://xxx.xxx.xxx:0000";   //服务器地址
    private String userName = "";   //账号
    private String passWord = "";   //密码
    private static String topic = "";   //订阅名
    private String clientId = Settings.Secure.ANDROID_ID;   //客户端ID
    private int qos = 2;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        init();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private void init() {
        Log.i(TAG, "initMqtt");
        // 服务器地址(协议+地址+端口号)
        client = new MqttAndroidClient(App.instance(), serverURI, clientId);
        conOpt = new MqttConnectOptions();
        // 清除缓存
        conOpt.setCleanSession(true);
        // 设置超时时间,单位:秒
        conOpt.setConnectionTimeout(10);
        // 心跳包发送间隔,单位:秒
        conOpt.setKeepAliveInterval(20);
        // 用户名
        conOpt.setUserName(userName);
        // 密码
        conOpt.setPassword(passWord.toCharArray());
        try {
            // 设置MQTT监听并且接受消息
            client.setCallback(mqttCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // last will message
        boolean doConnect = true;
        // 最后
        try {
            conOpt.setWill(topic, clientId.getBytes(), qos, false);
        } catch (Exception e) {
            e.printStackTrace();
            doConnect = false;
            iMqttActionListener.onFailure(null, e);
        }

        if (doConnect) {
            doClientConnection();
        }

    }

    /**
     * 连接MQTT服务器
     */
    private void doClientConnection() {
        try {
            if (!client.isConnected() && isConnectIsNomarl()) {
                client.connect(conOpt, null, iMqttActionListener);
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    // MQTT是否连接成功
    IMqttActionListener iMqttActionListener = new IMqttActionListener() {

        @Override
        public void onSuccess(IMqttToken arg0) {
            Log.i(TAG, "connect onSuccess " + topic);
            try {
                // 订阅myTopic话题,当订阅多条频道,需要遍历逐条订阅,否则有可能订阅失败
                client.subscribe(topic, qos, null, new IMqttActionListener() {
                    @Override
                    public void onSuccess(IMqttToken asyncActionToken) {
                        Log.i(TAG, "subscribe onSuccess ");
                    }

                    @Override
                    public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                        exception.printStackTrace();
                        Log.e(TAG, "subscribe onFailure ");
                    }
                });
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            Log.e(TAG, "connect onFailure ");
            arg1.printStackTrace();
            doClientConnection();//连接失败,重连(可关闭服务器进行模拟)
        }
    };

    // MQTT监听并且接受消息
    MqttCallback mqttCallback = new MqttCallback() {

        @Override
        public void messageArrived(String topic, MqttMessage message) {
            Log.i(TAG, "messageArrived:" + new String(message.getPayload()));
            //订阅信息,接收的信息message
            try {
                if (TextUtils.isEmpty(new String(message.getPayload()))) {
                    return;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {
            Log.e(TAG, "deliveryComplete");
        }

        @Override
        public void connectionLost(Throwable arg0) {
            Log.e(TAG, "connectionLost");
            // 如果是登录状态 失去连接,重连
                doClientConnection();
        }
    };

    /**
     * 判断网络是否连接
     */
    private boolean isConnectIsNomarl() {
        ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        return info != null && info.isAvailable();
    }


    //发布消息 msg
    public static void publish(String msg) {
        try {
            client.publish(topic, msg.getBytes(), 2, false);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开启服务
     *
     * @param context
     */
    public static void startService(Context context) {
        context.startService(new Intent(context, MqttService.class));
    }

    public static void stopService(Context context) {
        context.stopService(new Intent(context, MqttService.class));
    }


    @Override
    public void onDestroy() {
        try {
            if (client != null) {
                client.disconnect();  //服务销毁,断开连接
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

}

最后调用即可使用

//启动服务
 MqttService.startService(this);

最后总结下遇到的问题
不可识别的包(32108)
解决:换了serverURI的端口号即可

相关错误码:
1=无效协议版本
2=无效客户机标识
3=代理程序不可用
4=错误的用户名或密码
5=无权连接
6=意外错误
32000=等待来自服务器的响应时超时
32100=已连接客户机
32101=已断开客户机连接
32102=客户机正在断开连接
32103=无法连接至服务器
32104=客户机未连接
32105=指定的 SocketFactory 类型与代理程序 URI 不匹配
32106=SSL 配置错误
32107=不允许通过回调方法断开连接
32108=不可识别的包
32109=已断开连接
32110=已在进行连接
32111=客户机已关闭
32200=持久性已在使用中
32201=令牌已在使用中
32202=正在进行过多的发布

你可能感兴趣的:(android)