采用MQTT协议实现Android APP与阿里云平台的毗连

打印 上一主题 下一主题

主题 506|帖子 506|积分 1518

前言

信赖APP+单片机是很多同砚毕设大概课设的模式,上学期做课设的时候用到了MQTT协议毗连阿里云平台实现数据的通讯,也是根据网上大佬的经验做的,中间也踩了很多坑。本文将先容Android APP 通过MQTT协议与阿里云云平台毗连的内容,希望对各人能有所资助。

一、MQTT原理

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议MQTT最大长处在于,用少少的代码和有限的带宽,为毗连长途装备提供及时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型装备、移动应用等方面有较广泛的应用。
MQTT使用的发布/订阅消息模式,它提供了一对多的消息分发机制,从而实现与应用程序的解耦。
这是一种消息通报模式,消息不是直接从发送器发送到吸收器(即点对点),而是由MQTT Broker分发的。

在计划中,阿里云服务器作为一个消息中转站,即
下位机→MQTT Broker→云平台(流转)→MQTT Broker →上位机
二、创建APP

提示:以下非零基础可以跳过
1.创建APP项目,选择Empty Activity


2.设置UI
创建完后会有一个空白的Activity,找到res/layout目录下的的activity_main.xml文件,在这里编写UI。
这里我的UI界面仅供参考,因为项目尚有其他功能,这里只讲述MQTT的毗连,不需要的BUTTON控件可以自行删除。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"
  4.     xmlns:tools="http://schemas.android.com/tools"
  5.     android:layout_width="match_parent"
  6.     android:layout_height="match_parent"
  7.     android:orientation="vertical">
  8.     <LinearLayout
  9.         android:layout_width="match_parent"
  10.         android:layout_height="match_parent"
  11.         android:background="#078307"
  12.         android:orientation="vertical">
  13.         <RelativeLayout
  14.             android:layout_width="match_parent"
  15.             android:layout_height="78dp"
  16.             android:layout_marginTop="30dp"
  17.             android:background="@color/green">
  18.             <TextView
  19.                 android:layout_width="match_parent"
  20.                 android:layout_height="wrap_content"
  21.                 android:layout_centerInParent="true"
  22.                 android:layout_marginTop="10dp"
  23.                 android:gravity="center"
  24.                 android:text="基于人脸识别的小区门禁系统"
  25.                 android:textColor="@color/white"
  26.                 android:textSize="24sp" />
  27.         </RelativeLayout>
  28.         <LinearLayout
  29.             android:layout_width="match_parent"
  30.             android:layout_height="match_parent"
  31.             android:background="#FAF6F6"
  32.             android:orientation="vertical">
  33.             <LinearLayout
  34.                 android:layout_width="match_parent"
  35.                 android:layout_height="wrap_content"
  36.                 android:layout_marginTop="20dp"
  37.                 android:gravity="center">
  38.                 <ImageView
  39.                     android:id="@+id/m_im_1"
  40.                     android:layout_width="match_parent"
  41.                     android:layout_height="200dp"
  42.                     android:layout_marginLeft="10dp"
  43.                     android:layout_marginRight="10dp"
  44.                     android:scaleType="fitXY"
  45.                     android:src="@drawable/img" />
  46.             </LinearLayout>
  47.             <LinearLayout
  48.                 android:layout_width="match_parent"
  49.                 android:layout_height="300dp"
  50.                 android:layout_marginTop="30dp"
  51.                 android:orientation="vertical">
  52.                 <RelativeLayout
  53.                     android:layout_width="match_parent"
  54.                     android:layout_height="wrap_content"
  55.                     android:orientation="horizontal">
  56.                     <TextView
  57.                         android:layout_width="325dp"
  58.                         android:layout_height="60dp"
  59.                         android:layout_centerInParent="true"
  60.                         android:layout_marginBottom="20dp"
  61.                         android:background="@drawable/login_shape"
  62.                         android:gravity="center"
  63.                         android:text="请选择验证方式"
  64.                         android:textColor="@color/white"
  65.                         android:textSize="30dp" />
  66.                 </RelativeLayout>
  67.                 <LinearLayout
  68.                     android:layout_width="match_parent"
  69.                     android:layout_height="220dp"
  70.                     android:gravity="center"
  71.                     android:orientation="vertical">
  72.                     <Button
  73.                         android:id="@+id/Rfid"
  74.                         android:layout_width="150dp"
  75.                         android:layout_height="40dp"
  76.                         android:background="@drawable/button_selector"
  77.                         android:text="RFID刷卡验证"
  78.                         android:textColor="@color/white" />
  79.                     <Button
  80.                         android:id="@+id/face_recognition"
  81.                         android:layout_width="150dp"
  82.                         android:layout_height="40dp"
  83.                         android:layout_marginTop="15dp"
  84.                         android:background="@drawable/button_selector"
  85.                         android:text="人脸验证"
  86.                         android:textColor="@color/white" />
  87.                     <Button
  88.                         android:id="@+id/password_check"
  89.                         android:layout_width="150dp"
  90.                         android:layout_height="40dp"
  91.                         android:layout_marginTop="15dp"
  92.                         android:background="@drawable/button_selector"
  93.                         android:text="密码验证"
  94.                         android:textColor="@color/white" />
  95.                     <Button
  96.                         android:id="@+id/exit"
  97.                         android:layout_width="150dp"
  98.                         android:layout_height="40dp"
  99.                         android:layout_marginTop="15dp"
  100.                         android:background="@drawable/button_selector"
  101.                         android:text="退出"
  102.                         android:textColor="@color/white" />
  103.                 </LinearLayout>
  104.             </LinearLayout>
  105.             <LinearLayout
  106.                 android:layout_width="match_parent"
  107.                 android:layout_height="wrap_content"
  108.                 android:padding="25dp">
  109.                 <TextView
  110.                     android:layout_width="wrap_content"
  111.                     android:layout_height="wrap_content"
  112.                     android:text="MQTT连接状态:"
  113.                     android:textColor="@color/black"
  114.                     android:textSize="16sp" />
  115.                 <TextView
  116.                     android:id="@+id/m_mqtt"
  117.                     android:layout_width="wrap_content"
  118.                     android:layout_height="wrap_content"
  119.                     android:text=" "
  120.                     android:textColor="@color/black"
  121.                     android:textSize="16sp" />
  122.             </LinearLayout>
  123.         </LinearLayout>
  124.     </LinearLayout>
  125. </LinearLayout>
复制代码
3.添加mqtt包的依赖
在项目标build.gradle 中添加一行implementation 'org.eclipse.pahorg.eclipse.paho.client.mqttv3:1.2.0'
如下图

4.联网权限配置
在AndroidManifest.xml文件中添加`
  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <!--允许程序获取网络状态-->
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> `
复制代码

到这里Android项目就创建完成啦
三、创建阿里云产品

登录阿里云平台后,根据指示找到物联网平台

进入后创建产品,有一个30天免费试用的产品,建议把支付宝的自动续费关闭。进入后就可以开始创建产品,详细产品的参数设置已经记不清了,当时的产品也已经被接纳了,可以参考一下别的博客。

产品创建完成后需要创建装备,这里需要创建一个上位机和下位机,这里下位机用的是树莓派。

装备创建完成后在装备信息中会给出MQTT的毗连参数,需要我们在Android APP和树莓派代码中进行配置。

在这里装备就创建好了,但是还没完成,还需要配置解析器。
这里需要用到的是云产品流转。
这里在云产品流转功能中创建了两个解析器,绑定命据源和数据目标,并编写解析器的脚本。数据源和数据目标根据解析器ID确定,解析器脚本即读取转发的数据。注意,解析器只能识别JSON格式数据和二进制,这里推荐使用JSON格式。
示例脚本如下:
  1. var data = payload("json");
  2. writeIotTopic(1004,"/ionmnFFCKzs/shumeipai/user/get",data);
复制代码

通过payload函数,获取装备上报的消息内容,并按照JSON格式转换。
然后将消息发送给树莓派吸收的Topic。
通过日志服务可以监控到消息转发的过程,如下图所示:

这里消息质量使用的是Qos1,至少保证传一次。
数据流如下:

四、编写代码

如今到了编写代码部分,如果你的功能较多,需要跳转页面,建议把MQTT挂在后台,防止切屏的时候MQTT毗连断开,从而导致数据丢包。
起首是配置MQTT的参数配置,根据上文中MQTT配置信息复制粘贴过去。
添加代码全面飘红?不要慌,因为你还没有完成构建,很多类还没导入,逐个alt+enter导入即可。
  1.     private Handler handler;
  2.     private SqliteDBHelper mHelper;
  3.     private MqttClient client;
  4.     private final String host = "";
  5.     private final String userName = "";
  6.     private final String passWord = "";
  7.     private final String ClientId = "";
  8.     private final String mqtt_sub_topic = "";//订阅话题
  9.     private final String mqtt_pub_topic = "";//发布话题
  10.     private MqttConnectOptions mqttConnectOptions;
复制代码
  1. protected void onCreate(Bundle savedInstanceState) {
  2.         super.onCreate(savedInstanceState);
  3.         Objects.requireNonNull(getSupportActionBar()).hide();//这种方式默认式亮色主题
  4.         setContentView(R.layout.activity_main_desk);
  5.         TextView m_mqtt = findViewById(R.id.m_mqtt);//获取控件,不需要的控件自行删除
  6.         Button Rfid = findViewById(R.id.Rfid);
  7.         Button face_recognition = findViewById(R.id.face_recognition);
  8.         Button password_check = findViewById(R.id.password_check);
  9.         Button exit = findViewById(R.id.exit);
  10.         Mqtt_init();
  11.         startReconnect();
  12.         handler = new Handler(Looper.myLooper()) {//用于处理
  13.             @SuppressLint("SetTextI18n")
  14.             public void handleMessage(Message msg) {
  15.                 super.handleMessage(msg);
  16.                 switch (msg.what) {
  17.                     case 1: //开机校验更新回传
  18.                         break;
  19.                     case 2:  // 反馈回传
  20.                         break;
  21.                     case 3:  //MQTT 收到消息回传
  22.                         System.out.println(msg.obj.toString());   // 显示MQTT数据
  23.                         break;
  24.                     case 31:   //连接成功
  25.                         m_mqtt.setText("连接成功");//连接成功后按钮变为可点击状态
  26.                         Rfid.setOnClickListener(MainDeskActivity.this);
  27.                         face_recognition.setOnClickListener(MainDeskActivity.this);
  28.                         password_check.setOnClickListener(MainDeskActivity.this);
  29.                         exit.setOnClickListener(MainDeskActivity.this);
  30.                         try {
  31.                             client.subscribe(mqtt_sub_topic, 1);//订阅
  32.                         } catch (MqttException e) {
  33.                             e.printStackTrace();
  34.                         }
  35.                         break;
  36.                     case 30:  //连接失败
  37.                         Toast.makeText(MainDeskActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
  38.                         m_mqtt.setText("连接失败");
  39.                         break;
  40.                     default:
  41.                         break;
  42.                 }
  43.             }
  44.         };
  45.     }
复制代码
Mqtt_init函数
需要注意的一点是如果你的MQTT毗连断开后就无法重连上,建议将会话心跳设置长一点
  1. private void Mqtt_init() {
  2.         try {
  3.             client = new MqttClient(host, ClientId, new MemoryPersistence());
  4.             //MQTT的连接设置
  5.             mqttConnectOptions = new MqttConnectOptions();
  6.             mqttConnectOptions.setCleanSession(false);
  7.             mqttConnectOptions.setUserName(userName);
  8.             mqttConnectOptions.setPassword(passWord.toCharArray());
  9.             mqttConnectOptions.setConnectionTimeout(10);
  10.             
  11.             // 设置会话心跳时间 单位为秒 服务器会每隔1.5*30秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
  12.             //由于自身网络延时很难确定,建议设大一点,防止断开连接后无法重连
  13.             mqttConnectOptions.setKeepAliveInterval(30);
  14.             //设置回调
  15.             client.setCallback(new MqttCallback() {
  16.                 @Override
  17.                 public void connectionLost(Throwable cause) {
  18.                     //连接丢失后,一般在这里面进行重连
  19.                     System.out.println("connectionLost----------");
  20.                     startReconnect();
  21.                 }
  22.                 @Override
  23.                 public void deliveryComplete(IMqttDeliveryToken token) {
  24.                     //publish后会执行到这里
  25.                     System.out.println("deliveryComplete---------"
  26.                             + token.isComplete());
  27.                 }
  28.                 @Override
  29.                 public void messageArrived(String topicName, MqttMessage message)
  30.                         throws Exception {
  31.                     //subscribe后得到的消息会执行到这里面
  32.                     System.out.println("messageArrived----------");
  33.                 }
  34.             });
  35.         } catch (Exception e) {
  36.             e.printStackTrace();
  37.         }
  38.     }
复制代码
  1. MQTT连接函数
复制代码
  1.     // MQTT连接函数
  2.     private void Mqtt_connect() {        new Thread(new Runnable() {            @Override            public void run() {                try {                    if (!client.isConnected())  //如果还未毗连                    {                        client.connect(mqttConnectOptions);                        Message msg = new Message();                        msg.what = 31;                        handler.sendMessage(msg);                    }                } catch (Exception e) {                    e.printStackTrace();                    e.getMessage();                    Message msg = new Message();                    msg.what = 30;                    handler.sendMessage(msg);                }            }        }).start();    }
复制代码
MQTT重连函数
  1. // MQTT重新连接函数
  2.     private void startReconnect() {
  3.         ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
  4.         scheduler.scheduleAtFixedRate(new Runnable() {
  5.             @Override
  6.             public void run() {
  7.                 if (!client.isConnected()) {
  8.                     Mqtt_connect();
  9.                 }
  10.             }
  11.         }0, 1000, 10 * 1000, TimeUnit.MILLISECONDS);
  12.     }
复制代码
  1. MQTT发布订阅
复制代码
  1.     // 订阅函数    (下发任务/命令)
  2.     private void publish_message_plus(String topic, String message2) {
  3.         if (client == null || !client.isConnected()) {
  4.             return;
  5.         }
  6.         MqttMessage message = new MqttMessage();
  7.         message.setPayload(message2.getBytes());
  8.         message.setQos(1);//设置消息质量
  9.         //MQTT一共有三种消息质量
  10.         //Qos0:会发生消息的丢失或重复
  11.         //Qos1:至少送达一次
  12.         //Qos2:保证只送达到目标端一次,网络开销最高
  13.         try {
  14.             client.publish(topic, message);
  15.         } catch (MqttException e) {
  16.             e.printStackTrace();
  17.         }
  18.     }
复制代码
附上JSON数据的处置惩罚,其中message是MessageArrived中收到的数据,将message转为jsonObject对象后通过键获取值。
这里只用到了简朴的处置惩罚。假设收到的数据是"{\"flag\":\"02\"}\n"
  1. JSONObject jsonObject = new JSONObject(message.toString());
  2. int flag = jsonObject.getString("flag");
复制代码
五、完成测试

以上准备工作完成后就可以进行测试了,这里可以采用MQTT.fx软件来模拟下位机来发送信息,官网下载最新版http://mqttfx.org,由于只有三个月的免费试用,我的已经做不了演示了,详细操作可以自行网络搜索。联调乐成后就可以对下位机进行配置了。
MQTT毗连乐成后如下图所示:

可以根据自己功能的需要添加点击事件以及消息处置惩罚的逻辑,有问题欢迎私信。
总结

本文重要讲述了利用MQTT协议实现Android app与阿里云平台的毗连,流程并不难,新手会因为不认识而踩一些坑。在调试过程中,建议利用MQTT.fx分别对上位机和下位机调试,便于排盘问题。消息吸收失败可以在云平台上和MQTT.fx的日志里追踪消息。难点需要掌握Handler的回传机制,便于进行逻辑的编写。第一次开源,编写不易,如果帮到你的话可以点个赞吗。
参考资料
   https://blog.csdn.net/x97666/article/details/125172129

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

万万哇

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表