Introduction to MQTT Android client
.
brief introduction
MQTT (Message Queuing Telemetry Transport) is an instant messaging protocol developed by IBM.
It is a publish / subscribe, extremely simple and lightweight messaging protocol designed for limited devices and low bandwidth, high latency or unreliable networks. Its design idea is light, open, simple, standardized and easy to implement. These characteristics make it a good choice for many scenarios, especially for limited environments, such as machine to machine communication (M2M) and Internet of things. Compared with XMPP, MQTT is more lightweight and occupies less broadband.
.
.
Introduction to MQTT architecture
network connections
The architecture provided to MQTT by the underlying transport protocol
- The underlying transport protocol can connect the client and server
- The underlying transport protocol provides an orderly, reliable, bidirectional byte stream
Application message
Refers to the application data transmitted in the network through MQTT. When the application message is transmitted through MQTT, it will be attached with quality of service (QoS) and topic name.
client
Refers to the program or equipment using MQTT. The client always connects to the server. It can
- Publish application messages that other clients may be interested in
- Subscribe to the application messages you are interested in
- Unsubscribe application message
- Disconnect from the server
Server
Act as an intermediary between clients who subscribe to or publish application messages. One server
- Accept client's network connection
- Accept application messages published by the client
- Handle client subscription and unsubscribe requests
- Forward application messages matching client subscriptions
subscribe
A subscription consists of a topic filter and a maximum QoS. A subscription can only be associated with one session. A session can contain multiple subscriptions. Each subscription has a different topic filter.
Topic name
It refers to the label attached to the application message, which is used by the server to match the subscription. The server sends a copy of application information to each matched client.
Topic filter
An expression contained in the subscription to represent one or more topics of interest. Topic filters can contain wildcards.
conversation
The interaction between a stateful client and a server. Some sessions depend on network connections, while others can span multiple continuous network connections between a client and a server.
MQTT control package
A packet containing certain information sent over a network connection. The MQTT specification defines 14 different types of control packets, one of which (PUBLISH packet) is used to transmit application information.
.
.
Advantages of MQTT
.
-
Lightweight and efficient, minimizing resources required for client and network bandwidth
-
Use publish / subscribe message mode to provide one to many message publishing and decouple applications
-
Message transmission shielded from payload content
-
Provide network connection using TCP/IP (persistent session)
-
Use SSL/TLS to provide network security and trust
-
It has a "will" function, which notifies the subscriber client to disconnect abnormally from the MQTT server
-
Quality of service (QoS) levels can be specified to support message reliability
- qos is 0: "at least once", and the message publishing completely depends on the underlying TCP/IP network. Message loss or duplication can occur. This level can be used in the following situations: it doesn't matter if the environment sensor data is lost, because there will be a second transmission in the near future
- qos is 1: "at least once", which ensures that the message arrives, but message duplication may occur. This level can be used in the following situations. You need to get every message, and the repeated sending of messages has no impact on your usage scenario
- qos is 2: "only once", which ensures that the message arrives once. This level can be used in the following situations. In the billing system, repeated or lost messages will lead to incorrect results
.
.
MQTT core parameter description:
.
-
Topic: it means "topic" in Chinese. Clients who subscribe to the same topic in MQTT will receive message push at the same time. Directly realize the "group chat" function
-
clientId: unique ID of the customer
-
qos: quality of service
-
retained: to retain the last disconnected information
-
userName: the user name to connect to the MQTT server
-
passWord: passWord to connect to MQTT server
.
.
Introduction to the main methods of MQTT:
.
1. connect() method
Function: connect to MQTT server
Parameter Description:
- options: used to carry a series of parameters for connecting to the server, such as user name, password, etc.
- userContext: optional object used to pass context to callback. Generally, it can be passed to null.
- Callback: a callback used to monitor whether MQTT is successfully connected
@Override public IMqttToken connect(MqttConnectOptions options, Object userContext, IMqttActionListener callback) throws MqttException { //... }
.
2. publish() method
Function: publish messages and push messages to the server. Send a message to a topic, and then the server will push it to all customers who subscribe to this topic
Parameter Description:
- Topic: the topic of the published message
- payload: byte array of message contents
- qos: provides the quality of service of messages, which can be transmitted to 0, 1 or 2
- retained: whether to keep the last message after disconnection on the server
@Override public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean retained) throws MqttException, MqttPersistenceException { //... }
.
3. subscribe() method
Role: subscribe to message topics
Parameter Description:
- Topic: the topic of the subscription message
- qos: the quality of service of subscription messages, which can be transmitted to 0, 1 or 2
@Override public IMqttToken subscribe(String topic, int qos) throws MqttException, MqttSecurityException { //... }
.
.
Introduction to MQTT Android client
.
In the global build Add to gradle file
repositories { maven { url "https://repo.eclipse.org/content/repositories/paho-snapshots/" } }
.
.
In the project build Add dependency to gradle file
dependencies { implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' }
.
At androidmanifest XML add the following restrictions
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
.
At androidmanifest XML registration Service
<!--MqttService--> <service android:name="org.eclipse.paho.android.service.MqttService" />
.
The specific implementation is as follows:
public class MQTTManager { private final String TAG = "MQTTManager" private static MQTTManager instance = null; private String host = ""; //Server address (protocol + address + port number) private String userName = "";//User name to connect to MQTT server private String password = "";//Password to connect to MQTT server private String[] topics;//Subscribed 1 topic private String clientId =""; private MqttClient client;//mqtt client object private MqttConnectOptions conOpt;//MQTT connection option object //Callback of message private MqttCallback mCallback = new MyMqttCallback(); //Double check lock mode of singleton public synchronized static MQTTManager getInstance() { if (instance == null) { instance = new MQTTManager(); } return instance; } //Create connection (initialize MQTT client) public void createConnect(Context context, String host, String userName, String password, String[] topics) { this.host = host; this.userName = userName; this.password = password; //Client ID (unique identification number of the device, permission needs to be given first) if(getDeviceID(context) != ""){ clientId = getDeviceID(context); } //Gets the temporary cache directory of the operating system String tmpDir = System.getProperty("java.io.tmpdir"); //Data buffer MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir); try { //Create an MQTT connection option object and initialize it conOpt = new MqttConnectOptions(); conOpt.setCleanSession(true);// Clear cache conOpt.setConnectionTimeout(10);//Set timeout in seconds conOpt.setKeepAliveInterval(20);// Heartbeat packet sending interval, unit: S conOpt.setAutomaticReconnect(true);//Set whether the client will automatically attempt to reconnect to the server if the connection is lost // User name and password if( password != null && userName != null) { conOpt.setUserName(userName); conOpt.setPassword(password.toCharArray()); } //Create MQTT client object client = new MqttClient(host, clientId, dataStore); // Set MQTT to listen and accept messages client.setCallback(mCallback); if( topics != null) { this.topics = topics; client.subscribe(topics); } } catch (MqttException e) { e.printStackTrace(); } //Connect to MQTT server doConnect(); } //Connect to MQTT server public void doConnect() { if (client != null&& !mqttAndroidClient.isConnected() && isConnectIsNomarl()) { try { /** * options: It is used to carry a series of parameters for connecting to the server, such as user name, password, etc * userContext: Optional object to pass context to the callback. Generally, it can be passed to null * callback: Callback used to monitor whether MQTT is successfully connected * */ client.connect(conOpt, null, iMqttActionListener); } catch (Exception e) { e.printStackTrace(); } } } //Callback to connect to the server private IMqttActionListener iMqttActionListener = new IMqttActionListener() { @Override //Connection successful public void onSuccess(IMqttToken arg0) { Log.i(TAG, "Connection successful "); try { // Subscribe to topics client.subscribe(topics,2); } catch (MqttException e) { e.printStackTrace(); } } @Override // Connection failed, reconnect public void onFailure(IMqttToken arg0, Throwable arg1) { doConnect() //Connection failed, reconnect (you can shut down the server for simulation) Log.i(TAG, "connection failed "+arg1.printStackTrace()); } }; //Re subscribe to topics public void subscribeTopics(String[] topics) throws MqttException { if(topics !=null){ this.topics = topics; } /** * topic: The subject of the subscription message * qos: The quality of service of the subscription message can be transmitted to 0, 1 or 2 * */ client.subscribe(topics,2); } //Publish message (true: indicates that the sending is successful; false: indicates that the sending fails) public boolean publish(String topicName, int qos, String msg) { try { if (client == null || !client.isConnected()) { return false; } //Create and configure messages MqttMessage message = null; try { //Initialize message object message = new MqttMessage(msg.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } message.setQos(qos); /** * topic: Subject of the announcement * payload: Byte array of messages * qos: Provides the quality of service of messages, which can be transmitted to 0, 1 or 2 * retained: Do you want to keep the last message after disconnection on the server * */ client.publish(topicName, message); return true; } catch (MqttException e) { Log.e("mq", e.toString()); } return false; } //Cancel connection public void disConnect() throws MqttException { if (client != null && client.isConnected()) { client.disconnect(); } } //Disconnect public void close() { if (client != null && client.isConnected()) { try { client.disconnect(); } catch (MqttException e) { e.printStackTrace(); } } } //Get the device ID of the mobile phone as the ID of the MQTT client public static String getDeviceID(Context context) { TelephonyManager tm = (TelephonyManager) context.getSystemService(Activity.TELEPHONY_SERVICE); if (tm != null) { return tm.getDeviceId(); } return ""; } //Judge whether the network is connected private boolean isConnectIsNomarl() { ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connectivityManager.getActiveNetworkInfo(); if (info != null && info.isAvailable()) { String name = info.getTypeName(); Log.i(TAG, "Current network name:" + name); return true; } else { Log.i(TAG, "No network available"); /*When there is no available network, delay 3 seconds before trying to reconnect*/ new Handler().postDelayed(new Runnable() { @Override public void run() { doConnect(); } }, 3000); return false; } } }
.
Callback to receive information sent by MQTT server
public class MyMqttCallback implements MqttCallbackExtended { @Override /** *This method is called when a message arrives from the server * topic:The name of the message subject is published to * message:Actual information * */ public void messageArrived(String topic, MqttMessage message) throws Exception { String str1 = new String(message.getPayload()); Log.i("TAG", "Receive content:" + str1); Log.i("TAG", "Subscribed Topic:" + topic); response(topic,1,"Message received"); } @Override //Called when the message delivery is complete and all acknowledgments have been received public void deliveryComplete(IMqttDeliveryToken token) { } @Override public void connectComplete(boolean reconnect, String serverURI) { } @Override //This method is called when the connection to the server is lost public void connectionLost(Throwable cause) { // Lost connection } } //Response (after receiving the message from the server and the client, respond to inform the other party that the message has arrived or that there is a problem with the message, etc.) public void response(String topic,int qos,String message) { Boolean retained = false; try { //The parameters are: subject, byte array of message, quality of service, and whether to keep the last message after disconnection in the server mqttAndroidClient.publish(topic, message.getBytes(), qos.intValue(), retained.booleanValue()); } catch (MqttException e) { e.printStackTrace(); } }
.
Use of MQTT
Writing a Service class to call the methods in the above MQTTManager class can realize the function of MQTT. How to write it is not introduced here, but to call the methods directly.
.
.