前言:
亲测可行,本文实现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
?本文参考的APP源码:GitCode - 开发者的代码家园
下载链接: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目录
?
点击项目页面最右边的设置按钮,选择 Project Structure..
?
进入后,按如下图顺序点击选择?
?
在step1. 处输入路径 libs\org.eclipse.paho.client.mqttv3-1.2.2.jar
?
导入mqtt.jar包成功,点击ok
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="灭灯" />