【Android+物联网】Android封装MQTT连接阿里云物联网平台

前言:

亲测可行,本文实现Android封装MQTT连接阿里云物联网平台。将MQTT协议和连接阿里云平台的操作通过Android studio写入APP中,并简单设计UI。实现手机APP远程控制单片机LED灯亮灭的功能。

关于《Android软件开发》,见如下专栏

https://blog.csdn.net/m0_61712829/category_12455686.html?spm=1001.2014.3001.5482

 关于《完整实现STM32+ESP8266+MQTT+阿里云+APP》,见如下专栏

https://blog.csdn.net/m0_61712829/category_12545281.html?spm=1001.2014.3001.5482

源码可于上方资源绑定栏下载。

1.下载mqtt.jar包

下载链接:Index of /repositories/paho-releases/org/eclipse/paho

选取org.eclipse.paho.client.mqttv3/1.2.2/org.eclipse.paho.client.mqttv3-1.2.2.jar下载

进入链接后,过程如下:

首先,选取 org.eclipse.paho.client.mqttv3/ 
 

​选择 1.2.1/

选取 org.eclipse.paho.client.mqttv3-1.2.2.jar 进行下载

下载成功如下

然后,将下载成功的jar包拷贝到你工程的app/libs目录

2.导入mqtt.jar包

点击项目页面最右边的设置按钮,选择 Project Structure..

进入后,按如下图顺序点击选择 

在step1. 处输入路径 libs\org.eclipse.paho.client.mqttv3-1.2.2.jar

导入mqtt.jar包成功,点击ok

​ 3.程序说明

1.在 AndroidManifest.xml 添加网络权限

</application>
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

 位置如下所示:

​ 2.在 MainActivity.java 添加包

MainActivity.java 在如下位置

注意:将代码中涉及的工程名改为你的工程名 

package com.example.test;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;


import com.example.test.AliyunIoTSignUtil;

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.persist.MemoryPersistence;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

 3.在MainActivity.java中的public class MainActivity extends AppCompatActivity {}中初始定义一些基本信息

注意:将productKey、deviceName、deviceSecret 改为你自己的;将json数据格式中的标识符改为你自己的

 private static final String TAG =MainActivity.class.getSimpleName();

    private TextView msgTextView;

    private String productKey="a16OKk6dTya";
    private String deviceName="KAMI";
    private String deviceSecret="8790bd0545dd874d77fcac85729fc4bf";

    private final String payloadJson1="{\"ParkingState\":1}";
    private final String payloadJson2="{\"ParkingState\":0}";
    private MqttClient mqttClient=null;

    final int POST_DEVICE_PROPERTIES_SUCCESS = 1002;
    final int POST_DEVICE_PROPERTIES_ERROR = 1003;

    private String responseBody = "";


    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case POST_DEVICE_PROPERTIES_SUCCESS:
                    showToast("发送数据成功");
                    break;
                case POST_DEVICE_PROPERTIES_ERROR:
                    showToast("post数据失败");
                    break;
            }
        }
    };

 4.在MainActivity.java中,写开始APP生命周期函数

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         msgTextView = findViewById(R.id.msgTextView);

        findViewById(R.id.activate_button).setOnClickListener((l) -> {
            new Thread(() -> initAliyunIoTClient()).start();
        });

        findViewById(R.id.post_button1).setOnClickListener((l) -> {
            mHandler.postDelayed(() -> postDeviceProperties1(), 1000);
        });

        findViewById(R.id.post_button2).setOnClickListener((l) -> {
            mHandler.postDelayed(() -> postDeviceProperties2(), 1000);
        });
     }

5.在MainActivity.java中,写连接阿里云物联网平台函数

 private void initAliyunIoTClient() {

        try {
            String clientId = "12345"+ System.currentTimeMillis();

            Map<String, String> params = new HashMap<String, String>(16);
            params.put("productKey", productKey);
            params.put("deviceName", deviceName);
            params.put("clientId", clientId);
            String timestamp = String.valueOf(System.currentTimeMillis());
            params.put("timestamp", timestamp);

            // cn-shanghai
            String targetServer ="tcp://"+ productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";

            String mqttclientId = clientId + "|securemode=3,signmethod=hmacsha1,timestamp=" + timestamp + "|";
            String mqttUsername = deviceName + "&" + productKey;
            String mqttPassword = AliyunIoTSignUtil.sign(params, deviceSecret, "hmacsha1");

            connectMqtt(targetServer, mqttclientId, mqttUsername, mqttPassword);


        } catch (Exception e) {
            e.printStackTrace();
            responseBody = e.getMessage();
            mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_ERROR);
        }
    }

6.在MainActivity.java中,写登陆MQTT函数

 public void connectMqtt(String url, String clientId, String mqttUsername, String mqttPassword) throws Exception {

        MemoryPersistence persistence = new MemoryPersistence();
        mqttClient = new MqttClient(url, clientId, persistence);
        MqttConnectOptions connOpts = new MqttConnectOptions();
        // MQTT 3.1.1
        connOpts.setMqttVersion(4);
        connOpts.setAutomaticReconnect(true);
        connOpts.setCleanSession(true);

        connOpts.setUserName(mqttUsername);
        connOpts.setPassword(mqttPassword.toCharArray());
        connOpts.setKeepAliveInterval(60);

        mqttClient.connect(connOpts);
        Log.d(TAG, "connected " + url);

    }

7.在MainActivity.java中,写发布主题Publish函数

    private void postDeviceProperties1() {

        try {

            Random random = new Random();

            //上报数据
            String payload = String.format(payloadJson1, String.valueOf(System.currentTimeMillis()), 10 + random.nextInt(20), 50 + random.nextInt(50));
            responseBody = payload;
            MqttMessage message = new MqttMessage(payload.getBytes("utf-8"));
            message.setQos(1);


            String pubTopic = "/" + productKey + "/" + deviceName + "/user/update";
            mqttClient.publish(pubTopic, message);
            Log.d(TAG, "publish topic=" + pubTopic + ",payload=" + payload);
            mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_SUCCESS);

            mHandler.postDelayed(() -> postDeviceProperties1(), 5 * 1000);
        } catch (Exception e) {
            e.printStackTrace();
            responseBody = e.getMessage();
            mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_ERROR);
            Log.e(TAG, "postDeviceProperties error " + e.getMessage(), e);
        }
    }

    private void postDeviceProperties2() {

        try {

            Random random = new Random();

            //上报数据
            String payload = String.format(payloadJson2, String.valueOf(System.currentTimeMillis()), 10 + random.nextInt(20), 50 + random.nextInt(50));
            responseBody = payload;
            MqttMessage message = new MqttMessage(payload.getBytes("utf-8"));
            message.setQos(1);


            String pubTopic = "/" + productKey + "/" + deviceName + "/user/update";
            mqttClient.publish(pubTopic, message);
            Log.d(TAG, "publish topic=" + pubTopic + ",payload=" + payload);
            mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_SUCCESS);

            mHandler.postDelayed(() -> postDeviceProperties2(), 5 * 1000);
        } catch (Exception e) {
            e.printStackTrace();
            responseBody = e.getMessage();
            mHandler.sendEmptyMessage(POST_DEVICE_PROPERTIES_ERROR);
            Log.e(TAG, "postDeviceProperties error " + e.getMessage(), e);
        }
    }
    private void showToast(String msg) {
        msgTextView.setText(msg + "\n" + responseBody);
    }

}

8.解码获取password,在《物联网却不能物物相联?阿里云物联网平台得这么设置!》里面如果得到了password,不用这个class也行

在如下位置添加 AliyunIoTSignUtil.java

 AliyunIoTSignUtil.java中的代码如下

package com.example.test;

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

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

public class AliyunIoTSignUtil {

    public static String sign(Map<String, String> params, String deviceSecret, String signMethod) {
        //将参数Key按字典顺序排序
        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);
        }
    }

    /**
     * HMACSHA1加密
     *
     */
    public static 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);
    }

    public static final 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();
    }

}

9. 简单UI设计

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/msgTextView"
        android:layout_width="62dp"
        android:layout_height="563dp"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:padding="10dp"
        android:text="就你也会点灯?"
        android:textColor="#E91E63"
        android:textSize="36sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.536"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="128dp" />

    <Button
        android:id="@+id/activate_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginTop="7dp"
        android:layout_marginEnd="232dp"
        android:layout_marginRight="232dp"
        android:padding="10dp"
        android:text="激活"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="274dp" />

    <Button
        android:id="@+id/post_button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="205dp"
        android:layout_marginLeft="205dp"
        android:layout_marginTop="6dp"
        android:layout_marginBottom="10dp"
        android:padding="10dp"
        android:text="点灯"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="351dp" />

    <Button
        android:id="@+id/post_button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_marginTop="6dp"
        android:layout_marginEnd="10dp"
        android:text="灭灯" />


参考链接:跟我做,让Android封装MQTT连接阿里云平台!【开源】_跟我做,让安卓封装mqtt-CSDN博客

 本文参考的APP源码:GitCode - 开发者的代码家园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/314385.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能小程序小部件(Widget)开发详解

Widget 代表应用的一个小部件&#xff0c;负责小部件的展示和交互。 小部件(Widget) 的开发在智能小程序的基础上增加一个目录即可&#xff0c;用于存放小部件(Widget)的代码。并在 project.tuya.json 中增加一个声明。 创建小部件(Widget)项目 在 Tuya MiniApp Tools 中&…

【DotNetGuide】C#/.NET/.NET Core学习、工作、面试指南

&#x1f431;‍&#x1f680;C#/.NET/.NET Core学习、工作、面试指南 “ 让现在的自己不再迷茫✨✨✨。 GitHub开源地址&#xff1a;https://github.com/YSGStudyHards/DotNetGuide &#x1f4da;DotNetGuide简介 现如今网上关于Java、前端、Android、Golang...等相关技术的…

基础篇_面向对象(什么是对象,对象演化,继承,多态,封装,接口,Service,核心类库,异常处理)

文章目录 一. 什么是对象1. 抽取属性2. 字段默认值3. this4. 无参构造5. 抽取行为 二. 对象演化1. 对象字段演化2. 对象方法演化3. 贷款计算器 - 对象改造4. 静态变量5. 四种变量 三. 继承1. 继承语法2. 贷款计算器 - 继承改造3. java 类型系统4. 类型转换1) 基本类型转换2) 包…

数据结构04附录01:字符串大写转小写[C++]

图源&#xff1a;文心一言 上机题目练习整理~&#x1f95d;&#x1f95d; 本篇作为字符串的代码补充&#xff0c;提供了3种&#xff08;差别并不大&#xff09;解法以及函数的详细解释&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 前文&#xff1a;&#x1f338;…

最全的软件测试面试题(含答案)

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;软件测试面试题分享&#xff1a; 1000道软件测试面试题及答案&#x1f4e2;软件测试实战项目分享&#xff1a; 纯接口项目-完…

ME6211C33M5G-N 输出3.3V 500mA 线性稳压器LDO 参数

描述 ME6211系列是高精度&#xff0c;低噪声&#xff0c;CMOS LDO电压调压器。ME6211系列提供低输出噪声&#xff0c;高纹波抑制率&#xff0c;低辍学率和非常快速的开启时间&#xff0c;ME6211系列是当今最前沿的手机的理想选择。ME6211内部包括参考电压源、误差放大器、驱动…

Python从入门到精通 第十一章(面向对象)

一、类和对象 1、面向对象基本概念 &#xff08;1&#xff09;之前学习的编程方式是面向过程的&#xff0c;面向过程和面向对象是两种不同的编程方式。 &#xff08;2&#xff09;过程和函数&#xff1a;过程是早期的一个编程概念&#xff0c;过程类似于函数&#xff0c;只能…

DDNS-GO配置使用教程

环境&#xff1a;openwrt 下载地址&#xff1a;Releases jeessy2/ddns-go GitHub 下载 ssh至openwrt根目录&#xff0c;根据你的处理器选择要下载的版本&#xff0c;我是路由器&#xff0c;选择的是 ddns-go_5.7.1_linux_arm64.tar.gz wget github链接 安装 tar -zxvf…

对象图作业

对象图作业 一. 简答题&#xff08;共3题&#xff0c;100分&#xff09; (简答题) 对象特性的三要素是什么&#xff0c;请通过一个实际的例子来说明三要素的内容。 正确答案&#xff1a; 对象特性的三要素是状态、行为和标识。 张三对象具有身高、体重、学历、职务、收入等状态…

Flink 2.0 状态管理存算分离架构演进

Flink 2.0 状态管理存算分离架构演进 flink 现有状态访问线程模型首先简单来说一下,flink2.0做存算分离,最最主要的一点是解决,大状态的问题,例如一个超过50T的物流数据,大状态恢复可能就要1天,所以才有存算分离这么一个设计初衷。 下面先来看一下 任务是怎么执行提交的,…

浅研究下 DHCP 和 chrony

服务程序&#xff1a; 1.如果有默认配置&#xff0c;请先备份&#xff0c;再进行修改 2.修改完配置文件&#xff0c;请重启服务或重新加载配置文件&#xff0c;否则不生效 有些软件&#xff0c;安装包的名字和系统里服务程序的名字不一样&#xff08;安装包名字&#xff1a;…

Springboot+vue学生考试系统

Springbootvue学生考试系统 演示视频 【Springbootvue学生考试系统】 https://www.bilibili.com/video/BV1gk4y1Q7em/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 主要功能&#xff1a; 管理员可以添加题库分配课程教师&#xff0c;指定考试范围指定…

【教3妹学编程-算法题】统计出现过一次的公共字符串

3妹&#xff1a;哈哈哈哈哈哈&#xff0c;太搞笑了~ 呵呵呵呵呵呵 2哥&#xff1a;3妹干嘛呢&#xff0c; 笑的这么魔性&#xff01; 3妹&#xff1a;在看王牌对王牌&#xff0c;老搞笑了 2哥&#xff1a;这季好像没有贾玲吧。 3妹&#xff1a;是啊&#xff0c;听说贾玲去导电影…

仿真验证方法(2)——静态验证

一、静态验证 1.1 概述 在之前的文章中&#xff0c;我们介绍了动态仿真&#xff0c;但是动态仿真用于百万门以上电路时所需时间极长&#xff0c;而且其功能覆盖率取决于所设计的输入激励向量&#xff0c;很难达到100%&#xff0c;因此静态时序分析和等效性检查这样的静态验证是…

MySQL篇—自带物理克隆数据工具Clone插件介绍(第一篇,总共三篇)

各位小伙伴&#xff0c;今天我为大家介绍一下MySQL Clone Plugin这个插件&#xff0c;简单来说&#xff0c;就是MySQL 8.0.17版本之后的一个物理克隆数据工具&#xff0c;它能够帮助我们快速、高效地克隆或复制数据库&#xff0c;极大地简化了数据库迁移、备份和恢复的过程&…

老老实实的程序员该如何描述自己的缺点

答辩的时候&#xff0c;晋升的时候&#xff0c;面试的时候&#xff0c;你有没有经常遇到一个问题&#xff0c;那就是你觉得自己有什么缺点吗&#xff1f; 目录 1. 每个人都有缺点 2. 这道题在考什么&#xff1f; 3. 我之前是怎么回答的 4. 你可以这样回答试一试 5. 总结 …

transbigdata笔记:数据栅格化

1 area_to_grid 在边界或形状中生成矩形栅格 1.1 主要使用方法 transbigdata.area_to_grid(location, accuracy500, methodrect, paramsauto) 1.2 主要参数 location (bounds(List) or shape(GeoDataFrame) 生成栅格的位置。 如果边界为 [lon1&#xff0c; lat1&#xff0…

JS中垃圾数据是如何自动回收的

JS中垃圾数据是如何自动回收的 背景垃圾回收机制调用栈中的数据回收堆空间中数据回收垃圾回收器的工作流程副垃圾回收器主垃圾回收器 全停顿 背景 在JS栈和堆&#xff1a;数据是如何存储的一文中提到了 JavaScript 中的数据是如何存储的&#xff0c;并通过示例代码分析了原始数…

MySQL深入——9

如何正确的显示随机信息&#xff1f; 我们来模拟在英语单词app当中随机出现三个英语单词的情况&#xff0c;我们首先创建一张表words&#xff0c;然后给这个表当中插入10000条信息进行量化。 select word from words order by rand() limit 3&#xff1b; order by rand&…

Python - 操作 docx

文章目录 使用库 : python-docx 官方文档&#xff1a;https://python-docx.readthedocs.io 安装 pip install python-docx提取 docx from docx import Documentdoc Document(file_path) text "" for para in doc.paragraphs:text para.text "\n"创建…