一、概述

本项目制作了一个手机端APP,一个遥控器,通过MQTT协议连接阿里云,实现对下位机的操控,并监控下位机的状态。使用Paho接入物联网平台,参考阿里云Paho-MQTT Android接入示例。鉴于阿里云示例项目使用的android studio版本较老,且恰逢android studio 2022.3.1版本发布,本项目就使用了最新的版本完成该项目。

二、开发步骤

1、工程创建

工程创建和之前的版本没有太大区别,这里就不详述了。

2、导入库文件

这里使用了两个库文件,一个是org.eclipse.paho.client.mqttv3-1.2.5.jar,另一个是org.eclipse.paho.android.service-1.1.1.jar。实际上,后面这个库可以不用的,这里用它的原因是mqtt库不支持自动重连,而后面这个库支持。导入方法有两种:一是如下图所示,直接下载文件包粘贴到app下的libs文件夹下,右键导入即可;另一种就是在app模块的build.gradle文件中implementation,效果是一样的。网络不好的情况还是建议使用第一种方法。

 3、添加依赖

在工程的settings.gradle中添加Paho仓库地址。

 4、添加support-v4对应的兼容包

 5、开启网络权限,添加服务

 6、代码编写

6.1布局

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"

android:orientation="vertical"

android:background="#c0ffff"

tools:context=".MainActivity">

android:layout_width="match_parent"

android:layout_height="80dp"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:weightSum="4">

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:layout_width="60dp"

android:layout_height="match_parent"

android:text="状态:"

android:textSize="30dp"

android:layout_weight="1"/>

android:id="@+id/textView"

android:layout_width="60dp"

android:layout_height="match_parent"

android:background="#FFFFFF"

android:gravity="center"

android:text=" "

android:textSize="30dp"

android:layout_weight="1"/>

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:layout_width="match_parent"

android:layout_height="80dp"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:weightSum="5">

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:id="@+id/btn_open"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"

android:textSize="25dp"

android:text="开门" />

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:id="@+id/btn_close"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="1"

android:textSize="25dp"

android:text="关门" />

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:layout_width="match_parent"

android:layout_height="30dp"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:gravity="center"

android:weightSum="5">

android:id="@+id/btn_pause"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="1"

android:textSize="25dp"

android:text="暂停" />

android:layout_width="match_parent"

android:layout_height="30dp"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:weightSum="5">

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:id="@+id/btn_lock"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="1"

android:textSize="25dp"

android:text="锁门" />

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:id="@+id/btn_unlock"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="1"

android:textSize="25dp"

android:text="解锁" />

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="1"/>

6.1运行代码

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;

import android.graphics.Color;

import android.os.Bundle;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

import org.eclipse.paho.android.service.MqttAndroidClient;

import org.eclipse.paho.client.mqttv3.IMqttActionListener;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;

import org.eclipse.paho.client.mqttv3.IMqttToken;

import org.eclipse.paho.client.mqttv3.MqttCallback;

import org.eclipse.paho.client.mqttv3.MqttConnectOptions;

import org.eclipse.paho.client.mqttv3.MqttException;

import org.eclipse.paho.client.mqttv3.MqttMessage;

import org.json.JSONException;

import org.json.JSONObject;

import java.math.BigInteger;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

/**************************************************************/

public class MainActivity extends AppCompatActivity {

/* MQTT客户端对象 */

MqttAndroidClient mqttAndroidClient;

final private String TAG = "AiotMqtt";

/* 设备三元组信息 */

final private String PRODUCTKEY = "";//填自己的

final private String DEVICENAME = "";//填自己的

final private String DEVICESECRET = "";//填自己的

/* 自动Topic, 用于上报消息 */

final private String PUB_TOPIC = "/" + PRODUCTKEY + "/" + DEVICENAME + "/user/update";

/* 自动Topic, 用于接受消息 */

final private String SUB_TOPIC = "/" + PRODUCTKEY + "/" + DEVICENAME + "/user/get";

/* 阿里云Mqtt服务器域名 */

final String host = "tcp://" + PRODUCTKEY + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";

private String clientId;

private String userName;

private String passWord;

/************************************************************/

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

/* MQTT初始化 */

mqttInit();

/* MQTT连接 */

mqttConnect();

/* 通过按键发布消息 */

Button[] arrButton = new Button[5];

buttonInit(arrButton);

buttonHandler(arrButton,Color.BLUE, Color.RED);

}/* onCreate */

/************************************************************

*

************************************************************/

/* MQTT初始化函数 */

private void mqttInit() {

/* 获取Mqtt建连信息clientId, username, password */

AiotMqttOption aiotMqttOption = new AiotMqttOption().getMqttOption(PRODUCTKEY, DEVICENAME, DEVICESECRET);

if (aiotMqttOption == null) {

Log.e(TAG, "device info error");

} else {

clientId = aiotMqttOption.getClientId();

userName = aiotMqttOption.getUsername();

passWord = aiotMqttOption.getPassword();

}

/* 创建MqttAndroidClient对象, 并设置回调接口 */

mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), host, clientId);

mqttAndroidClient.setCallback(new MqttCallback() {

@Override

public void connectionLost(Throwable cause) {

Log.i(TAG, "connection lost");

}

@Override

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

Log.i(TAG, "topic: " + topic + ", msg: " + new String(message.getPayload()));

String payload = new String(message.getPayload());

TextView recText = findViewById(R.id.textView);

recText.setText(jsonParser(payload));

}

@Override

public void deliveryComplete(IMqttDeliveryToken token) {

Log.i(TAG, "msg delivered");

}

});

}

/************************************************************/

/* MQTT连接函数 */

private void mqttConnect() {

/* 创建MqttConnectOptions对象并配置username和password */

MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();

mqttConnectOptions.setUserName(userName);

mqttConnectOptions.setPassword(passWord.toCharArray());

/* Mqtt建连 */

try {

mqttAndroidClient.connect(mqttConnectOptions,null, new IMqttActionListener() {

@Override

public void onSuccess(IMqttToken asyncActionToken) {

Log.i(TAG, "connect succeed");

subscribeTopic(SUB_TOPIC);

}

@Override

public void onFailure(IMqttToken asyncActionToken, Throwable exception) {

Log.i(TAG, "connect failed");

}

});

} catch (MqttException e) {

e.printStackTrace();

}

} /* mqttConnect */

/************************************************************/

/**

* 订阅特定的主题

* @param topic mqtt主题

*/

public void subscribeTopic(String topic) {

try {

mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {

@Override

public void onSuccess(IMqttToken asyncActionToken) {

Log.i(TAG, "subscribed succeed");

}

@Override

public void onFailure(IMqttToken asyncActionToken, Throwable exception) {

Log.i(TAG, "subscribed failed");

}

});

} catch (MqttException e) {

e.printStackTrace();

}

} /* subscribeTopic */

/************************************************************/

/**

* 向默认的主题/user/update发布消息

* @param payload 消息载荷

*/

public void publishMessage(String payload) {

try {

if (!mqttAndroidClient.isConnected()) {

mqttAndroidClient.connect();

}

MqttMessage message = new MqttMessage();

message.setPayload(payload.getBytes());

message.setQos(0);

mqttAndroidClient.publish(PUB_TOPIC, message,null, new IMqttActionListener() {

@Override

public void onSuccess(IMqttToken asyncActionToken) {

Log.i(TAG, "publish succeed!");

}

@Override

public void onFailure(IMqttToken asyncActionToken, Throwable exception) {

Log.i(TAG, "publish failed!");

}

});

} catch (MqttException e) {

Log.e(TAG, e.toString());

e.printStackTrace();

}

} /* publishMessage */

/************************************************************/

/**

* MQTT建连选项类,输入设备三元组productKey, deviceName和deviceSecret, 生成Mqtt建连参数clientId,username和password.

*/

static class AiotMqttOption {

private String username = "";//填自己的

private String password = "";//填自己的

private String clientId = "";//填自己的

public String getUsername() { return this.username;}

public String getPassword() { return this.password;}

public String getClientId() { return this.clientId;}

/**

* 获取Mqtt建连选项对象

* @param productKey 产品秘钥

* @param deviceName 设备名称

* @param deviceSecret 设备机密

* @return AiotMqttOption对象或者NULL

*/

public AiotMqttOption getMqttOption(String productKey, String deviceName, String deviceSecret) {

if (productKey == null || deviceName == null || deviceSecret == null) {

return null;

}

try {

String timestamp = Long.toString(System.currentTimeMillis());

// clientId

this.clientId = productKey + "." + deviceName + "|timestamp=" + timestamp +

",_v=paho-android-1.0.0,securemode=2,signmethod=hmacsha256|";

// userName

this.username = deviceName + "&" + productKey;

// password

String macSrc = "clientId" + productKey + "." + deviceName + "deviceName" +

deviceName + "productKey" + productKey + "timestamp" + timestamp;

String algorithm = "HmacSHA256";

Mac mac = Mac.getInstance(algorithm);

SecretKeySpec secretKeySpec = new SecretKeySpec(deviceSecret.getBytes(), algorithm);

mac.init(secretKeySpec);

byte[] macRes = mac.doFinal(macSrc.getBytes());

password = String.format("%064x", new BigInteger(1, macRes));

} catch (Exception e) {

e.printStackTrace();

return null;

}

return this;

}

} /* class AiotMqttOption */

/************************************************************/

/* 按键初始化函数 */

private void buttonInit(Button[] buttons){

for (int i = 0; i < buttons.length; ++i) {

switch (i){

case 0:

buttons[i] = findViewById(R.id.btn_open);

break;

case 1:

buttons[i] = findViewById(R.id.btn_close);

break;

case 2:

buttons[i] = findViewById(R.id.btn_pause);

break;

case 3:

buttons[i] = findViewById(R.id.btn_lock);

break;

case 4:

buttons[i] = findViewById(R.id.btn_unlock);

break;

}

}

} /* buttonInit */

/************************************************************/

@SuppressLint("ClickableViewAccessibility")

private void buttonHandler(Button[] button, int fColor, int bColor) {

for (int i = 0; i < button.length; ++i) {

int j = i;

button[i].setBackgroundColor(fColor);

button[i].setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View view, MotionEvent motionEvent) {

if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {

button[j].setBackgroundColor(bColor);

} else {

button[j].setBackgroundColor(fColor);

switch (j) {

case 0:

publishMessage("{\"state\":\"OPEN\"}");

break;

case 1:

publishMessage("{\"state\":\"CLOSE\"}");

break;

case 2:

publishMessage("{\"state\":\"PAUSE\"}");

break;

case 3:

publishMessage("{\"state\":\"LOCK\"}");

break;

case 4:

publishMessage("{\"state\":\"UNLOCK\"}");

break;

}

}

return false;

}

});

}

}/* buttonHandler */

/************************************************************/

/* json解析函数 */

private String jsonParser(String strIn){

String strOut = null;

/* 解析json数据 */

try {

JSONObject jsonObject = new JSONObject(strIn);

strOut = jsonObject.getString("state");

} catch (JSONException e) {

e.printStackTrace();

}

return strOut;

}

} /* MainActivity */

精彩文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: