IOT development---Android MQTT use

Introduction to MQTT

MQTT (Message Queuing Telemetry Transport, Message Queuing Telemetry Transport Protocol), is a "lightweight" communication protocol based on publish/subscribe (publish/subscribe) mode.

The protocol is built on the TCP/IP protocol, and its design idea is lightweight, open, simple, standardized, and easy to implement. These characteristics make it a good choice for many scenarios, especially for constrained environments such as machine-to-machine communication (M2M) and Internet of Things (IoT) environments.

MQTT communication model

The MQTT protocol provides one-to-many message publishing, which can reduce the coupling of applications. Users only need to write a small amount of application code to complete one-to-many message publishing and subscription. The protocol is based on the <client-server> model , there are three main identities in the protocol: Publisher, Broker, and Subscriber.

Among them, both the publisher and the subscriber of the MQTT message are clients, and the server is just a relay, forwarding the message published by the publisher to all subscribers who subscribe to the topic; the publisher can publish the information within its authority All topics, and message publishers can be subscribers at the same time, realizing the decoupling of producers and consumers, and the published messages can be subscribed by multiple subscribers at the same time.

The schematic diagram of the MQTT communication model is as follows:
insert image description here

MQTT client

The MQTT client can publish information to the server, and can also receive information from the server. We call the act of a client sending a message "publishing" a message. If the client wants to receive information from the server, it must first "subscribe" to the server.

The specific functions of the client are as follows:
1. Publish messages to other related clients.
2. Subscribe to the topic request to receive related application messages.
3. Unsubscribe topic request to remove receiving application messages.
4. Terminate the connection from the server.

MQTT server

The MQTT server is usually a server (broker), which is the hub of MQTT information transmission and is responsible for passing the information sent by the MQTT client to the MQTT client. The MQTT server is also responsible for managing the MQTT clients to ensure smooth communication between clients and ensure that MQTT information is received and delivered correctly.

The MQTT server is located between the message publisher and the subscriber, so as to receive the message and send it to the subscriber. Its functions are:
1. Accept the network connection request from the client.
2. Accept the application message issued by the client.
3. Handle the client's subscription and unsubscription requests.
4. Forward application messages to eligible subscribed clients (including the publisher itself).

Android uses MQTT

Integrated MQTT library

MQTT has many implementations in different languages ​​and versions, among which Eclipse Paho is just one of many Java implementations.

We will use the Eclipse Paho Java Client as the client, which is the most widely used MQTT client library in the Java language.

Integration steps:

  1. Add dependency packages to the bulid.gradle(:app) file of the Android project
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'

org.eclipse.paho also implements a communication service framework for Android https://github.com/eclipse/paho.mqtt.android

Many developers directly quote this library:

implementation ‘org.eclipse.paho:org.eclipse.paho.android.service:1.1.1’

It is no problem to do this before Android 8.0. After 8.0, the behavior of Android Service has changed a lot, and it needs to be adapted, otherwise an exception will occur. However, the maintainers of this library seem to be not very active in adapting the Android version. In view of this, we downloaded the source code of the library, modified the source code, and used it as a library project:

implementation project(':org.eclipse.paho.android.service')
  1. Add permissions
<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. Register Service
<service android:name="org.eclipse.paho.android.service.MqttService" />

Define the MQTT manager

This class is designed as a singleton mode to implement operations such as MQTT initialization, connection, message subscription, message publishing, message processing, and connection release.

Initialization includes creating an MqttAndroidClient object, setting a callback interface, trying to disconnect and reconnect if the connection fails, parsing the received message through JSON, repackaging it into the required data content, and throwing the message object through the EventBus. The relevant business module registers the EventBus and receives the corresponding message, and then processes it.

The connection is mainly to set the connection-related parameters and process the connection results. The parameters include connection authentication verification, timeout setting, heartbeat packet sending interval, user name and password setting.

/**
 * Created by ZhangJun on 2019/1/3.
 */
class MqttManager private constructor() {
    
    

    private var mqttAndroidClient: MqttAndroidClient? = null
    private lateinit var mqttConnectOptions: MqttConnectOptions

    private object MqttManagerHolder {
    
    
        val INSTANCE = MqttManager()
    }

    fun init(node: String, port: Int, clientId: String) {
    
    
        try {
    
    
            if (mqttAndroidClient == null) {
    
    
                mqttAndroidClient = MqttAndroidClient(XxApplication.instance, "ssl://$node:$port", clientId)
            } else {
    
    
                mqttAndroidClient!!.setCallback(object : MqttCallbackExtended {
    
    
                    override fun connectComplete(reconnect: Boolean, serverURI: String?) {
    
    
                        LogUtils.d(TAG, "mqtt connectComplete reconnect = $reconnect")
                    }

                    override fun connectionLost(cause: Throwable?) {
    
    
                        if (cause != null) {
    
    
                            LogUtils.d(TAG, "mqtt connectionLost cause = " + cause.message)
                        }
                        connect()
                    }

                    @Throws(Exception::class)
                    override fun messageArrived(topic: String, message: MqttMessage) {
    
    
                        val str = String(message.payload)
                        LogUtils.d(TAG, "messageArrived str = $str")
                        val jsonObject = JSONObject(str)
                        val event = jsonObject.optJSONObject("event")
                        val header = event.optJSONObject("header")
                        val namespace = header.optString("namespace")
                        val name = header.optString("name")
                        val payload = event.optJSONObject("payload")
                        val message1 = MqttMessageBean()
                        message1.messageId = namespace.plus(name)
                        message1.messageContent = payload
                        EventBus.getDefault().post(ServerEvent.MqttMessageEvent(message1))
                    }

                    override fun deliveryComplete(token: IMqttDeliveryToken) {
    
    
                        //do nothing
                    }
                })

                mqttConnectOptions = MqttConnectOptions()
                mqttConnectOptions.socketFactory = sslSocketFactory

                mqttConnectOptions.isAutomaticReconnect = true
                mqttConnectOptions.isCleanSession = false
                // 设置超时时间,单位:秒
                mqttConnectOptions.connectionTimeout = 10
                // 心跳包发送间隔,单位:秒
                mqttConnectOptions.keepAliveInterval = 20
                // 用户名
                mqttConnectOptions.userName = CommonUtils.decryptToken()
                // 密码
                mqttConnectOptions.password = XxApplication.instance.packageName.toCharArray()
                connect()
            }
        } catch (ex: Exception) {
    
    
            ex.printStackTrace()
        }
    }

    private fun connect() {
    
    
        if (mqttAndroidClient != null && !mqttAndroidClient!!.isConnected) {
    
    
            mqttAndroidClient!!.connect(mqttConnectOptions, null, object : IMqttActionListener {
    
    
                override fun onSuccess(asyncActionToken: IMqttToken) {
    
    
                    val disconnectedBufferOptions = DisconnectedBufferOptions()
                    disconnectedBufferOptions.bufferSize = 100
                    disconnectedBufferOptions.isBufferEnabled = true
                    disconnectedBufferOptions.isPersistBuffer = false
                    disconnectedBufferOptions.isDeleteOldestMessages = false
                    mqttAndroidClient!!.setBufferOpts(disconnectedBufferOptions)
                }

                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
    
    
                    LogUtils.d(TAG, " mqtt connect fail exception = " + exception.message)
                }
            })
        }
    }

    private val sslSocketFactory: SSLSocketFactory
        get() {
    
    
            try {
    
    
                val sslContext = SSLContext.getInstance("SSL")
                sslContext.init(null, trustManager, SecureRandom())
                return sslContext.socketFactory
            } catch (e: Exception) {
    
    
                throw RuntimeException(e)
            }

        }

    private val trustManager: Array<TrustManager>
        get() = arrayOf(object : X509TrustManager {
    
    
            override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
    
    
                //do nothing
            }

            override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
    
    
                //do nothing
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
    
    
                return arrayOf()
            }
        })

    /**
     * 订阅消息
     */
    fun subscribeTopic(subTopic: String, qos: Int) {
    
    
        try {
    
    
            if (mqttAndroidClient != null && mqttAndroidClient!!.isConnected) {
    
    
                mqttAndroidClient!!.subscribe(subTopic, qos)
            }
        } catch (ex: MqttException) {
    
    
            System.err.println("Exception while subscribing")
            ex.printStackTrace()
        }

    }

    /**
     * 发布消息
     */
    fun publishMessage(pubTopic: String, qos: Int, content: String) {
    
    
        try {
    
    
            if (mqttAndroidClient != null && mqttAndroidClient!!.isConnected) {
    
    
                mqttAndroidClient!!.publish(pubTopic, content.toByteArray(), qos, false)
            }
        } catch (e: MqttException) {
    
    
            System.err.println("Error Publishing: " + e.message)
            e.printStackTrace()
        }

    }

    fun release() {
    
    
        try {
    
    
            if (mqttAndroidClient != null) {
    
    
                mqttAndroidClient!!.unregisterResources()
                if (mqttAndroidClient!!.isConnected) {
    
    
                    mqttAndroidClient!!.disconnect()
                }
                mqttAndroidClient!!.close()
                mqttAndroidClient = null
            }
        } catch (e: Exception) {
    
    
            e.printStackTrace()
        }
    }

    companion object {
    
    
        private val TAG = MqttManager::class.java.simpleName

        val instance: MqttManager
            get() = MqttManagerHolder.INSTANCE
    }
}

Define the message entity

/**
 * Created by ZhangJun on 2019/1/5.
 */
class MqttMessageBean {
    
    
    var messageId: String = ""
    var messageContent: JSONObject = JSONObject()
}

Guess you like

Origin blog.csdn.net/johnWcheung/article/details/129480100