Android APP must-have advanced features, MQTT for message push

This article has authorized the original launch of the WeChat public account "Hongyang", please be sure to indicate the source when reprinting.

1. Several ways to implement message push on the Android side

  1. Polling: The client periodically requests data from the server. Fake push. Disadvantages: cost of electricity, cost of traffic.
  2. Block SMS messages. When the server needs to notify the client, it sends a short message. After the client receives a specific short message, it first obtains the information and then intercepts the short message. Fake push. Cons: Expensive and text messages can be intercepted by security software.
  3. Persistent connection (Push) mode: establishes a persistent connection between the client and the server. real push.
    1. Google's C2DM (Cloudto Device Messaging). It requires scientific Internet access, and most users in China cannot use it.
    2. XMPP. XMPP (Extensible Messaging and Presentation Protocol) is a protocol based on Extensible Markup Language (XML). androidpn is a java open source Android push notification implementation based on XMPP protocol. It contains a complete client and server side.
    3. MQTT. MQTT is a lightweight message publish/subscribe protocol, which is an ideal solution for implementing a message push server based on mobile phone clients.

2. Introduction to MQTT

MQTT official website: http://mqtt.org/

Introduction to MQTT: http://www.ibm.com

MQTT Android github:https://github.com/eclipse/paho.mqtt.android

MQTT API:http://www.eclipse.org/paho/files/javadoc/index.html

MQTT Android API: http://www.eclipse.org/paho/files/android-javadoc/index.html

It is recommended that students with sufficient time read the five links above in order, and students who do not have enough time, please see the following brief introduction (most of the content comes from the five links above).

The MQTT protocol is lightweight in the sense that
clients are small and the MQTT protocol uses network bandwidth efficiently. The MQTT protocol supports reliable delivery and fire-and-forget transport. In this protocol, messaging is decoupled from the application. The degree of separation from the application depends on how the MQTT client and MQTT server are written. Disconnected delivery frees the application from any server connections and waiting for messages. The interactive mode is similar to email, but optimized for application programming.

Protocols have many different functions:

  • It is a publish/subscribe protocol.
  • In addition to providing one-to-many message distribution, publish/subscribe is also out of the application. These features are useful for applications with multiple clients.
  • It has nothing to do with the message content.
  • It operates over TCP/IP, which provides basic network connectivity.
  • It provides three qualities of service for messaging:
    • "At most once"
      messages are delivered on a best-effort basis according to the underlying Internet Protocol network. Messages may be lost.
      For example, use this quality of service with communication environment sensor data. It doesn't matter if individual reads are lost or if new reads are issued immediately later.
    • Message arrival is guaranteed "at least once"
      , but duplicates may occur.
    • "Exactly Once"
      ensures that the message is received only once.
      For example, use this quality of service with a billing system. Duplicate or missing messages may cause inconvenience or wrong charges.
  • It is an economical way to manage the flow of messages in a network. For example, fixed-length headers are only 2 bytes long, and protocol switching minimizes network traffic.
  • It has a "will" feature that notifies subscribers that the client has abnormally disconnected from the MQTT server. See the " Last News " release.

3. MQTT server setup

  1. Click here to download the Apollo server, unzip it and install it.
  2. Enter the bin directory of the installation directory from the command line (for example: E:>cd E:\MQTT\apache-apollo-1.7.1\bin).
  3. Enter apollo create XXX (xxx is the name of the created server instance, for example: apollo create mybroker), and then a folder named XXX will be created in the bin directory. The etc\apollo.xml file in the XXX folder is the file for configuring server information. The etc\users.properties file contains the username and password used to connect to the MQTT server. The default is admin=password, that is, the account is admin and the password is password, which can be changed by yourself.
  4. Enter the XXX/bin directory, enter apollo-broker.cmd run to start the server, and see the following interface, which means the construction is complete

success

Then enter http://127.0.0.1:61680/ in the browser to see if the installation is successful.

4. MQTT Android client specific implementation

basic concept:

  • topic: Chinese means "topic". subscribeClients that subscribe ( ) to the same topic ( ) in MQTT topicwill receive push notifications at the same time. Direct realization of the "group chat" function.
  • clientId: The unique identifier of the client's identity.
  • qos: Quality of service.
  • retained: To retain the last disconnection information.
  • MqttAndroidClient#subscribe(): Subscribe to a topic.
  • MqttAndroidClient#publish(): Send a message to a topic, and then the server will push it to all clients subscribed to this topic.
  • userName: The username to connect to the MQTT server.
  • passWord : The password to connect to the MQTT server.

add dependencies

repositories {
    maven {
        url "https://repo.eclipse.org/content/repositories/paho-releases/"
    }
}

dependencies {
    compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.0'
}

Add permissions

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

Register Service

        <!-- Mqtt Service -->
        <service android:name="org.eclipse.paho.android.service.MqttService" />
        <service android:name="com.dongyk.service.MQTTService"/>

Android side specific implementation

package com.dongyk.service;

import android.app.Service;
...

/**
 * MQTT长连接服务
 *
 * @author 一口仨馍 联系方式 : [email protected]
 * @version 创建时间:2016/9/16 22:06
 */
public class MQTTService extends Service {

    public static final String TAG = MQTTService.class.getSimpleName();

    private static MqttAndroidClient client;
    private MqttConnectOptions conOpt;

//    private String host = "tcp://10.0.2.2:61613";
    private String host = "tcp://192.168.1.103:61613";
    private String userName = "admin";
    private String passWord = "password";
    private static String myTopic = "topic";
    private String clientId = "test";

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

    public static void publish(String msg){
        String topic = myTopic;
        Integer qos = 0;
        Boolean retained = false;
        try {
            client.publish(topic, msg.getBytes(), qos.intValue(), retained.booleanValue());
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    private void init() {
        // 服务器地址(协议+地址+端口号)
        String uri = host;
        client = new MqttAndroidClient(this, uri, clientId);
        // 设置MQTT监听并且接受消息
        client.setCallback(mqttCallback);

        conOpt = new MqttConnectOptions();
        // 清除缓存
        conOpt.setCleanSession(true);
        // 设置超时时间,单位:秒
        conOpt.setConnectionTimeout(10);
        // 心跳包发送间隔,单位:秒
        conOpt.setKeepAliveInterval(20);
        // 用户名
        conOpt.setUserName(userName);
        // 密码
        conOpt.setPassword(passWord.toCharArray());

        // last will message
        boolean doConnect = true;
        String message = "{\"terminal_uid\":\"" + clientId + "\"}";
        String topic = myTopic;
        Integer qos = 0;
        Boolean retained = false;
        if ((!message.equals("")) || (!topic.equals(""))) {
            // 最后的遗嘱
            try {
                conOpt.setWill(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
            } catch (Exception e) {
                Log.i(TAG, "Exception Occured", e);
                doConnect = false;
                iMqttActionListener.onFailure(null, e);
            }
        }

        if (doConnect) {
            doClientConnection();
        }

    }

    @Override
    public void onDestroy() {
        try {
            client.disconnect();
        } catch (MqttException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

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

    }

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

        @Override
        public void onSuccess(IMqttToken arg0) {
            Log.i(TAG, "连接成功 ");
            try {
                // 订阅myTopic话题
                client.subscribe(myTopic,1);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();
              // 连接失败,重连
        }
    };

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

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {

            String str1 = new String(message.getPayload());
            MQTTMessage msg = new MQTTMessage();
            msg.setMessage(str1);
            EventBus.getDefault().post(msg);
            String str2 = topic + ";qos:" + message.getQos() + ";retained:" + message.isRetained();
            Log.i(TAG, "messageArrived:" + str1);
            Log.i(TAG, str2);
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {

        }

        @Override
        public void connectionLost(Throwable arg0) {
            // 失去连接,重连
        }
    };

    /** 判断网络是否连接 */
    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, "MQTT当前网络名称:" + name);
            return true;
        } else {
            Log.i(TAG, "MQTT 没有可用网络");
            return false;
        }
    }

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

First initialize each parameter, and then connect to the server. After the connection is successful, at http://127.0.0.1:61680/ you can see that the name "topic" is automatically created topic. Here I use a real machine and an emulator to run the program. http://127.0.0.1:61680/ This is what the server sees

serverPic

There are two places to pay attention to here:
1. When the emulator is running host = "tcp://10.0.2.2:61613", because 10.0.2.2 is the specific ip set by the emulator, it is the alias of your computer. When the real machine is running host = "tcp://192.168.1.103:61613". 192.168.1.103 is the IPv4 address of my host, and the cmd command to view the local IP is ipconfig/all.
2. The two runtimes clientIdcannot be the same (in order to ensure the uniqueness of the client ID).

Here for testing, a MQTTServicepublic method is exposed in . code show as belowpublish(String msg)MainActivity

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
        startService(new Intent(this, MQTTService.class));
        findViewById(R.id.publishBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MQTTService.publish("CSDN 一口仨馍");
            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getMqttMessage(MQTTMessage mqttMessage){
        Log.i(MQTTService.TAG,"get message:"+mqttMessage.getMessage());
        Toast.makeText(this,mqttMessage.getMessage(),Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }

}

EventBus3.0Sending a message is used here . If you are interested, you can see the use of EventBus3.0 and source code analysis . Of course, you can also use the interface callback method or even pop up directly in the Service Toast. whatever, now click in one client MainActivity, Buttonboth clients have been able to pop up messages at the same time. Data has getarrived. Next, show time~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325543889&siteId=291194637