在全球智能手机市场里,谷歌开发的Android移动操作系统市场占有率已经高达90%。随着物联网智能硬件升级,也逐渐成为智能摄像头,智能对讲门禁,人脸识别闸机,智能电视,智能广告屏等 IoT 设备的首选操作系统。
《物联网开发实战》本期为大家详细讲解 Android 设备通过 MQTT 协议接入阿里云 IoT 物联网平台的完整过程。
目录:
阿里云 IoT 物联网云端开发
使用Android Studio开发设备端程序
联机运行,日志详解
IoT 物联网平台
1.免费开通阿里云 IoT物联网云服务:
https://www.aliyun.com/product/iot-deviceconnect
2.创建产品,选择自定义品类,直连设备:
3.添加产品功能定义,我们以采集Android设备的硬件厂商、型号、Android版本、SDK版本信息为例:
物模型属性通信Topic和Payload如下:
// 属性上报 Topic:
/sys/{productKey}/{deviceName}/thing/event/property/post
// 属性 Payload:
{
"id":123452452,
"version":"1.0",
"params":{
"brand":"HUAWEI",
"model":"ELE-AL00",
"android":"10",
"sdk":29
},
"method":"thing.event.property.post"
}
参考文档:
https://help.aliyun.com/document_detail/89301.html
4.注册设备,此时设备为未激活状态。
点击DeviceSecret的查看,获取身份三元组。
Android 设备开发
5.Android应用程序依赖
Gradle 配置:
repositories {
maven {
url "https://repo.eclipse.org/content/repositories/paho-releases/"
}
}
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.2'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
MANIFEST 配置:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application>
<!-- Mqtt Service -->
<service android:name="org.eclipse.paho.android.service.MqttService" />
</application>
6.设备三元组生成MQTT 的CONNECT参数转换工具
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.util.Map;
/**
* AliyunIoTSignUtil
*/
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();
}
}
7.设备发起建立 MQTT 连接
public void connectMqtt(String url, String clientId, String mqttUsername, String mqttPassword) throws Exception {
mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), url, clientId);
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);
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
postTopic();
}
@Override
public void connectionLost(Throwable cause) {
Log.d(TAG, "connectionLost " + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d(TAG, "messageArrived topic=" + topic+", message=" + new String(message.getPayload()));
//此处为收到的云端数据
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.d(TAG, "deliveryComplete token=" + token.toString());
}
});
mqttAndroidClient.connect(connOpts,null,
new IMqttActionListener(){
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "connect 回调 连接成功");
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(TAG, "connect 回调 onFailure,原因 exception=" + exception.toString());
}
});
}
8.设备上报物模型属性信息
public void postTopic(){
JSONObject params = new JSONObject();
params.put("brand",Build.BRAND);
params.put("model",Build.MODEL);
params.put("android",Build.VERSION.RELEASE);
params.put("sdk",Build.VERSION.SDK_INT);
JSONObject payload = new JSONObject();
payload.put("id",System.currentTimeMillis());
payload.put("version","1.0");
payload.put("params",params);
payload.put("method","thing.event.property.post");
MqttMessage message = new MqttMessage();
message.setPayload(payload.toString().getBytes("utf-8"));
message.setQos(0);
mqttAndroidClient.publish(postTopic, message);
}
联机运行
9.编译并部署程序到手机
10.查看设备详情,状态变为在线,物模型数据可以查看到Android设备的信息
11.日志服务查看属性上报完整日志:
通过观察日志,我们了解到物模型属性上报包含三个步骤:
设备publish数据到IoT平台
IoT物联网平台按照预先定义的物模型校验并存储数据
IoT物联网平台给设备响应物模型属性reply消息
完整源码获取方式: