Android -- MQTT消息推送实践

最近接到新需求,需要使用 MQTT 把大屏设备上的信息,比如用户使用信息,常用需求设置等共享到服务器,且能通过服务器动态设置大屏。所以,这里简单学习一些MQTT的知识。

代码工程: https://github.com/LillteZheng/MQTTDemo

一、MQTT 简介

MQTT 是IBM 开发的一款轻量级的即时通信协议;通过 发布/订阅 的模式,专门为受限设备或低宽带,高延迟等弱网环境而设计。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境。
而在集控领域也越来越受欢迎,本文的最后目的就是用于服务器与大屏的集控关系。

首先,需要先搭建好后台服务器,虽然一般这个为后台搭建,但是作为Android研发,也可以自己简单搭建一个服务器用于调试。

二、搭建服务器

搭建服务器,有很多选择,作为 Java 为基础开发语言的,所以需要 apache 的服务器,网上有很多教程,但都是 1.7.1 的版本,但是官网已经没有这个版本的软件了,不过可以通过以下链接去下载:
http://archive.apache.org/dist/activemq/activemq-apollo/1.7.1/

下载适合自己的版本,我这里是 window ,所以下载:
Android -- MQTT消息推送实践_第1张图片
下载解压,然后添加系统变量,即解压路径下的bin:
在这里插入图片描述
接着,创建服务:在 cmd 上,输入: apollo create server ( 其中 server 是服务的名字,自己写一个)如下:
Android -- MQTT消息推送实践_第2张图片
然后可以看到已经在 bin 文件下生成一个 server 的文件夹了:
Android -- MQTT消息推送实践_第3张图片
其中 etc 中包含了你的用户名和密码,分别是 admin 和 password;建议不去修改它,后面会用到。

接着,通过cmd 进入 bin 目录,执行:apollo-broker.cmd run 其中服务:
Android -- MQTT消息推送实践_第4张图片
说明服务已经启动完毕了。然后在浏览器上输入 http:127.0.0.1:61681 ,就可以看到画面了,账号密码就是 admin 和password。

上面还有 Accepting connections 的字段,表示可加入的host 和port ,这个接下来会用到。

MQTT.fx 调试

服务器已经搭建好了,需要来熟悉一下流程,首先,先下载 MQTT.fx ,下载地址如下:
http://www.jensd.de/apps/mqttfx/
一路安装启动即可。
启动客户端之后,点击设置:
Android -- MQTT消息推送实践_第5张图片
然后按照如下步骤:

  1. 新建一个 profiles
  2. 修改你的profiels name
  3. 输入服务的ip,即你的 ipv4 的地址
  4. 输入端口,还记得上面的 Accepting connections 吧,从那里选一个
  5. 修改 Client ID,这是唯一ID,后面在 Android 的客户端中,需要指定
  6. 填写 username 和 password

Android -- MQTT消息推送实践_第6张图片
点击ok之后,选择你刚才的profile,点击 connect
接着,点击 Subsribe 订阅,输入一个主题字段,这里用 dev/status 表示,然后点 subcribe 点阅即可。如下图:
Android -- MQTT消息推送实践_第7张图片
接着,点击 Publish ,发布你的主题,这里跟订阅的字段一样,然后输入你想发送给 主题 dev/status 的信息即可,然后点击 publish,如下:
Android -- MQTT消息推送实践_第8张图片
接着,回到 Subscribe ,就可以看到已经接受到信息了:
Android -- MQTT消息推送实践_第9张图片

ok,这样一种 订阅/发布 ,类似于观察者模式的流程,我们就熟悉了。接着,我们来实践一下 Android 的。

Android 客户端

要实现的效果是,Android 与 mqtt.fx 通信。

首先新建一个工程,然后再 project.gradle 中添加:

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url "https://repo.eclipse.org/content/repositories/paho-releases/"
        }
        
    }
}

build.gradle 中添加:

    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

然后,记得在 AndroidManifest.xml 中添加 MQTT 服务,不然会报错误:


添加权限:

    
    
    

接着,配置好我们的基本信息:

    private static final String HOST = "tcp://192.168.49.41:61613";
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "password";
    private static final String SUBSCRIBE_TOPIC = "dev/status";    //订阅主题
    private static final String PUBLISH_TOPIC = "dev/push";       //发布主题
    private static final String CLIENT_ID = "ANDROID_ID"; //客户端ID,避免与 MQTT.fx 冲突

因为Android 也属于一个客户端,所以为了避免和 mqtt.fx 冲突,这里的 CLIENT_ID 要与 mqtt.fx 不一样。
接着就是一些配置了:

private void initMQTT() {
        /**
         * 新建一个客户端,HOST 为 MQTT 地址,CLIENT_ID 为唯一标识
         */
        mClient = new MqttAndroidClient(this, HOST, CLIENT_ID);
        mClient.setCallback(new MQTTMessageListener());

        /**
         * 通过 options 配置客户端的信息,比如账号,密码,和最后的遗嘱等
         */
        MqttConnectOptions options = new MqttConnectOptions();

        //清除缓存
        options.setCleanSession(true);
        //超时
        options.setConnectionTimeout(10);
        //心跳包
        options.setKeepAliveInterval(20);
        //用户名和密码
        options.setUserName(USERNAME);
        options.setPassword(PASSWORD.toCharArray());


        /**
         * 设置最后的遗嘱,该方式可以让设备在掉线时,发送状态给服务器
         */
        String topic = SUBSCRIBE_TOPIC;
        String msg = "disconnect";
        /**
         * qos 表示传递的服务质量,它的参数有 0,1,2三种如下:
         * 0:发送一次,不需要确认
         * 1:至少一次确认
         * 2:发送必须确认
         * retained:是否在服务器保留断开连接后的最后一条消息
         */

        options.setWill(topic,msg.getBytes(),2,false);
        if (!mClient.isConnected()) {
            try {
                //连接服务器和监听消息
                mClient.connect(options, null, IMqttActionListener);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

可以看到,我们最终要看到的是 mClient.connect()这个方法,其中 opstion 为要配置的属性,第二个参数为 context 上下文,这里传 null 即可,第三个参数则是 listener 用来监听,是否能连接上服务器:

    /**
     * 检测到 MQTT 是否连接服务器
     */
    private IMqttActionListener IMqttActionListener = new IMqttActionListener() {

        @Override
        public void onSuccess(IMqttToken arg0) {
            //当连接上服务器,则可以订阅哪些主题了,这里也用 dev/status 这个主题
            Log.d(TAG, "zsr - 连接成功 ");
            try {
                // 订阅Topic话题,然后用 mqtt.fx 发消息过来
                mClient.subscribe(SUBSCRIBE_TOPIC,2);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();
            // 连接失败,重连
            Log.d(TAG, "zsr - onFailure: "+arg1.getMessage());
        }
    };

可以看到,在 onSuccess 方法中,订阅 topic 主题,这里用的是 dev/status 。其中当新消息过来的时候,在 MQTTMessageListener 里:

    /**
     * 监听是否收到信的消息
     */
    class MQTTMessageListener implements MqttCallback{

        @Override
        public void connectionLost(Throwable cause) {
            //连接失败
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            //新信息到达
            Log.d(TAG, "zsr - 收到新消息了: "+message);
            //当收到信息之后,我们回一条消息给 mqtt.fx
            publish(PUBLISH_TOPIC,"msg from android");
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            //发送成功
        }
    }

可以看到,当接收到 mqtt.fx 的信息之后,回送一条信息给 mqtt.fx ,内容非常简单。当然,还需要把 mqtt.fx 订阅的主题,改成我们android 客户端的 dev/push:
Android -- MQTT消息推送实践_第10张图片
最终效果如下:

Android -- MQTT消息推送实践_第11张图片

参考链接:
https://blog.csdn.net/qq_17250009/article/details/52774472
https://www.hivemq.com/blog/how-to-get-started-with-mqtt/
https://www.jianshu.com/p/73436a5cf855

你可能感兴趣的:(Android-网络,MQTT,MQTT.fx,即时通信)