android使用mqtt连接阿里云物联网平台

我的个人网站 http://www.cheese.ren/

博客来源 http://www.cheese.ren/blog/blog/334

欢迎交换友链 :-)


最近查看了一下阿里云物联网平台的文档,发现使用mqtt的连接方法并没有写的很清楚,就来稍微归纳一下


相关网站

MQTT:https://mqtt.org/ (物联网消息传递标准)

Eventbus:https://github.com/greenrobot/EventBus (Android和Java的发布/订阅事件总线)


在build.gradle中添加下列依赖

//MQTT
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
//Eventbus
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'org.greenrobot:eventbus:3.1.1'

重新Make Project一下即可


创建IoT.java

package com.example.fackunlocking;

import android.content.Context;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.greenrobot.eventbus.EventBus;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class IoT {
    private String productKey, deviceName, deviceSecret, regionId, topic; //基础配置

    private MqttClient mqttClient;


    public IoT(String productKey, String deviceName, String deviceSecret, String regionId) {
        this.productKey = productKey;
        this.deviceName = deviceName;
        this.deviceSecret = deviceSecret;
        this.regionId = regionId; //这里设置的是物联网平台的区域,例如“华东2(上海)”的值为“cn-shanghai”,具体地区对应的值请查看阿里云的文档
        topic = "/" + productKey + "/" + deviceName;
    }


    //连接
    public boolean connect() {
        try {
            //配置 服务器地址 客户端id 用户名 密码
            String clientId = "java" + System.currentTimeMillis();
            String timestamp = String.valueOf(System.currentTimeMillis());
            Map<String, String> params = new HashMap<>(16);
            params.put("productKey", productKey);
            params.put("deviceName", deviceName);
            params.put("clientId", clientId);
            params.put("timestamp", timestamp);
            String targetServer = "tcp://" + productKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883";
            String mqttClientId = clientId + "|securemode=3,signmethod=hmacsha1,timestamp=" + timestamp + "|";
            String mqttUsername = deviceName + "&" + productKey;
            String mqttPassword = sign(params, deviceSecret, "hmacsha1"); //获取密码
            //使用MQTT进行连接
            MemoryPersistence persistence = new MemoryPersistence();
            mqttClient = new MqttClient(targetServer, mqttClientId, persistence);
            MqttConnectOptions connectOptions = new MqttConnectOptions();
            connectOptions.setMqttVersion(4);
            connectOptions.setCleanSession(false);
            connectOptions.setAutomaticReconnect(false);
            connectOptions.setUserName(mqttUsername);
            connectOptions.setPassword(mqttPassword.toCharArray());
            connectOptions.setKeepAliveInterval(60);
            mqttClient.connect(connectOptions);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    //发布 topic是要发布的topic地址,只需补全剩下的地址即可 payload或许有一定的格式,可以在类中定义格式,本例子偷懒不写了=W=
    public boolean publish(String topic, String payload) {
        try {
            MqttMessage message = new MqttMessage(payload.getBytes("utf-8"));
            /*
                这里出现了Qos,稍微科普一下,后面就不再重复了
                参数0代表Sender发送的一条消息,Receiver最多能收到一次,也就是说Sender尽力向Receiver发送消息,如果发送失败,也就算了
                参数1代表Sender发送的一条消息,Receiver至少能收到一次,也就是说Sender向Receiver发送消息,如果发送失败,会继续重试,直到Receiver收到消息为止,但是因为重传的原因,Receiver有可能会收到重复的消息
                参数2代表Sender发送的一条消息,Receiver确保能收到而且只收到一次,也就是说Sender尽力向Receiver发送消息,如果发送失败,会继续重试,直到Receiver收到消息为止,同时保证Receiver不会因为消息重传而收到重复的消息
            */
            message.setQos(1);
            mqttClient.publish(topic, message);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    //订阅
    public boolean listen(Context context, String topic) {
        try {
            //注册广播
            EventBus.getDefault().register(this.connect());
            mqttClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {

                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    String str = new String(message.getPayload());
                    EventBus.getDefault().post(new MessageEvent(str));
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {

                }
            });
            MqttTopic mqttTopic = mqttClient.getTopic(topic);
            mqttClient.subscribe(topic, 1);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    //关闭连接
    public boolean close(Context context) {
        try {
            EventBus.getDefault().unregister(context);//注销广播
            mqttClient.disconnect();
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    private String sign(Map<String, String> params, String deviceSecret, String signMethod) {
        String[] sortedKeys = params.keySet().toArray(new String[]{});
        Arrays.sort(sortedKeys);
        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (String key : sortedKeys) {
            if ("sign".equalsIgnoreCase(key)) {
                continue;
            }
            canonicalizedQueryString.append(key).append(params.get(key));
        }
        try {
            String key = deviceSecret;
            return encryptHMAC(signMethod, canonicalizedQueryString.toString(), key);
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String encryptHMAC(String signMethod, String content, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes("utf-8"), signMethod);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        byte[] data = mac.doFinal(content.getBytes("utf-8"));
        return bytesToHexString(data);
    }

    private String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i=0; i<bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

}

发布消息的步骤

IoT iot = new IoT("productKey", "deviceName", "deviceSecret", "regionId")
iot.connect();

iot.publish("topic", "payload");

//用完请关掉!养成良好习惯!
//iot.close(Activity.this);

订阅消息的步骤

IoT iot = new IoT("productKey", "deviceName", "deviceSecret", "regionId")
iot.connect();

//订阅的方法
@RequiresApi(api = Build.VERSION_CODES.M)
@Subscribe(threadMode = ThreadMode.MAIN)
public void listenWay(MessageEvent messageEvent) {
    System.out.println(messageEvent.getMessage());
}

iot.listen(Activity.this, "topic");

//用完请关掉!养成良好习惯!
//iot.close(Activity.this);

当消息赶来时就会调用listenWay这个方法,很方便!


这样一个连接阿里云物联网平台的类就封装完成啦!或许有些地方不太准确,但大致意思是没错了的,更多的使用方法可以自行探索。

热门文章

暂无图片
编程学习 ·

那些年让我们目瞪口呆的bug

程序员一生与bug奋战&#xff0c;可谓是杀敌无数&#xff0c;见怪不怪了&#xff01;在某知识社交平台中&#xff0c;一个“有哪些让程序员目瞪口呆的bug”的话题引来了6700多万的阅读&#xff0c;可见程序员们对一个话题的敏感度有多高。 1、麻省理工“只能发500英里的邮件” …
暂无图片
编程学习 ·

redis的下载与安装

下载redis wget http://download.redis.io/releases/redis-5.0.0.tar.gz解压redis tar -zxvf redis-5.0.0.tar.gz编译 make安装 make install快链方便进入redis ln -s redis-5.0.0 redis
暂无图片
编程学习 ·

《大话数据结构》第三章学习笔记--线性表(一)

线性表的定义 线性表&#xff1a;零个或多个数据元素的有限序列。 线性表元素的个数n定义为线性表的长度。n为0时&#xff0c;为空表。 在比较复杂的线性表中&#xff0c;一个数据元素可以由若干个数据项组成。 线性表的存储结构 顺序存储结构 可以用C语言中的一维数组来…
暂无图片
编程学习 ·

对象的扩展

文章目录对象的扩展属性的简洁表示法属性名表达式方法的name属性属性的可枚举性和遍历可枚举性属性的遍历super关键字对象的扩展运算符解构赋值扩展运算符AggregateError错误对象对象的扩展 属性的简洁表示法 const foo bar; const baz {foo}; baz // {foo: "bar"…
暂无图片
编程学习 ·

让程序员最头疼的5种编程语言

世界上的编程语言&#xff0c;按照其应用领域&#xff0c;可以粗略地分成三类。 有的语言是多面手&#xff0c;在很多不同的领域都能派上用场。大家学过的编程语言很多都属于这一类&#xff0c;比如说 C&#xff0c;Java&#xff0c; Python。 有的语言专注于某一特定的领域&…
暂无图片
编程学习 ·

写论文注意事项

参考链接 给研究生修改了一篇论文后&#xff0c;该985博导几近崩溃…… 重点分析 摘要与结论几乎重合 这一条是我见过研究生论文中最常出现的事情&#xff0c;很多情况下&#xff0c;他们论文中摘要部分与结论部分重复率超过70%。对于摘要而言&#xff0c;首先要用一小句话引…
暂无图片
编程学习 ·

安卓 串口开发

上图&#xff1a; 上码&#xff1a; 在APP grable添加 // 串口 需要配合在项目build.gradle中的repositories添加 maven {url "https://jitpack.io" }implementation com.github.licheedev.Android-SerialPort-API:serialport:1.0.1implementation com.jakewhart…
暂无图片
编程学习 ·

2021-2027年中国铪市场调研与发展趋势分析报告

2021-2027年中国铪市场调研与发展趋势分析报告 本报告研究中国市场铪的生产、消费及进出口情况&#xff0c;重点关注在中国市场扮演重要角色的全球及本土铪生产商&#xff0c;呈现这些厂商在中国市场的铪销量、收入、价格、毛利率、市场份额等关键指标。此外&#xff0c;针对…
暂无图片
编程学习 ·

Aggressive cows题目翻译

描述&#xff1a; Farmer John has built a new long barn, with N (2 < N < 100,000) stalls.&#xff08;John农民已经新建了一个长畜棚带有N&#xff08;2<N<100000&#xff09;个牛棚&#xff09; The stalls are located along a straight line at positions…
暂无图片
编程学习 ·

剖析组建PMO的6个大坑︱PMO深度实践

随着事业环境因素的不断纷繁演进&#xff0c;项目时代正在悄悄来临。设立项目经理转岗、要求PMP等项目管理证书已是基操&#xff0c;越来越多的组织开始组建PMO团队&#xff0c;大有曾经公司纷纷建造中台的气质&#xff08;当然两者的本质并不相同&#xff0c;只是说明这个趋势…
暂无图片
编程学习 ·

Flowable入门系列文章118 - 进程实例 07

1、获取流程实例的变量 GET运行时/进程实例/ {processInstanceId} /变量/ {变量名} 表1.获取流程实例的变量 - URL参数 参数需要值描述processInstanceId是串将流程实例的id添加到变量中。变量名是串要获取的变量的名称。 表2.获取流程实例的变量 - 响应代码 响应码描述200指…
暂无图片
编程学习 ·

微信每天自动给女[男]朋友发早安和土味情话

微信通知&#xff0c;每天给女朋友发早安、情话、诗句、天气信息等~ 前言 之前逛GitHub的时候发现了一个自动签到的小工具&#xff0c;b站、掘金等都可以&#xff0c;我看了下源码发现也是很简洁&#xff0c;也尝试用了一下&#xff0c;配置也都很简单&#xff0c;主要是他有一…
暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

项目经理,你有什么优势吗?

大侠被一个问题问住了&#xff1a;你和别人比&#xff0c;你的优势是什么呢? 大侠听到这个问题后&#xff0c;脱口而出道&#xff1a;“项目管理能力和经验啊。” 听者抬头看了一下大侠&#xff0c;显然听者对大侠的这个回答不是很满意&#xff0c;但也没有继续追问。 大侠回家…
暂无图片
编程学习 ·

nginx的负载均衡和故障转移

#注&#xff1a;proxy_temp_path和proxy_cache_path指定的路径必须在同一分区 proxy_temp_path /data0/proxy_temp_dir; #设置Web缓存区名称为cache_one&#xff0c;内存缓存空间大小为200MB&#xff0c;1天没有被访问的内容自动清除&#xff0c;硬盘缓存空间大小为30GB。 pro…
暂无图片
编程学习 ·

业务逻辑漏洞

身份认证安全 绕过身份认证的几种方法 暴力破解 测试方法∶在没有验证码限制或者一次验证码可以多次使用的地方&#xff0c;可以分为以下几种情况︰ (1)爆破用户名。当输入的用户名不存在时&#xff0c;会显示请输入正确用户名&#xff0c;或者用户名不存在 (2)已知用户名。…