更新时间:2024-12-25 GMT+08:00

Android Demo使用说明

概述

本文以Android语言为例,介绍通过MQTTS/MQTT协议接入平台,基于平台接口实现“属性上报”“订阅接收命令”等功能。

本文中使用的代码为样例代码,仅用于体验平台通信功能,如需进行商用,可以参考资源获取获取对应语言的IoT Device SDK进行集成。

前提条件

准备工作

  • 安装android studio

    访问android studio官网,选择合适系统的版本下载并安装。(本文以windows 64-bit系统Android Studio 3.5为例)。

  • 安装JDK(也可以使用IDE自带的JDK)
    1. 访问Oracle官网,选择合适的JDK版本单击“Download”下载(本文以Windows x64 JDK8为例)。
    2. 下载完成后,运行安装文件,根据界面提示安装。

导入代码样例

  1. 下载quickStart(Android)样例。
  2. 运行Android Studio,单击Open,选择步骤1中下载的样例。

  3. 完成代码导入。

    代码目录简述:

    • manifests:Android项目的配置文件;
    • java项目java代码

      MainActivity:demo界面类;

      ConnectUtils:mqtt连接辅助类;

    • asset项目原生文件;

      DigiCertGlobalRootCA.bks:设备校验平台身份的证书,用于设备侧接入物联网平台登录鉴权使用;

    • res:项目资源文件(图片、布局、字符串等);
    • gradle:项目全局的gradle构建脚本.
    • libs项目中使用到了第三方jar包归档目录

      org.eclipse.paho.android.service-1.1.0.jar:Android启动后台service组件实现消息发布和订阅的组件;

      org.eclipse.paho.client.mqttv3-1.2.0.jar:mqtt java客户端组件;

  4. (可选)了解Demo里的关键工程配置(默认不用修改)。

    • AndroidManifest.xml:需要添加,支持mqtt service。
      <service android:name="org.eclipse.paho.android.service.MqttService" />
    • build.gradle:添加依赖,导入libs下的两个mqtt连接所需要的jar包。(也可以添加jar包官网引用)
      implementation files('libs/org.eclipse.paho.android.service-1.1.0.jar')
      implementation files('libs/org.eclipse.paho.client.mqttv3-1.2.0.jar')

界面展示

  1. MainActivity类主要提供了界面显示,请填写设备ID和设备密钥,在物联网平台或调用接口注册设备后获取。
  2. 示例中默认写了设备侧接入的域名地址(SSL加密接入时该域名要与对应的证书文件匹配使用)。
    private final static String IOT_PLATFORM_URL = "iot-mqtts.cn-north-4.myhuaweicloud.com";
  3. 用户可以选择设备侧建链时是否SSL加密/不加密,选择Qos方式是0还是1,当前不支持Qos2,可参考使用限制
    checkbox_mqtt_connet_ssl.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {    
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                isSSL = true;
                checkbox_mqtt_connet_ssl.setText("SSL加密");
            } else {
                isSSL = false;
                checkbox_mqtt_connet_ssl.setText("SSL不加密");
            }    
        }
    })

建立连接

设备或网关在接入物联网平台时首先需要和平台建立连接,从而将设备或网关与平台进行关联。开发者通过传入设备信息,将设备或网关连接到物联网平台。

  1. MainActivity类主要提供建立MQTT/MQTTS连接等方法,MQTT默认使用1883端口,MQTTS默认使用8883端口(需要加载证书)。
    if (isSSL) {
        editText_mqtt_log.append("开始建立MQTTS连接" + "\n");
        serverUrl = "ssl://" + IOT_PLATFORM_URL + ":8883";
    } else {
        editText_mqtt_log.append("开始建立MQTT连接" + "\n");
        serverUrl = "tcp://" + IOT_PLATFORM_URL + ":1883";
    }
  2. ConnectUtils类主要提供了SSL加载证书的getMqttsCerificate方法,如果是MQTTS建链方式,需要调用该方法加载证书。
    DigiCertGlobalRootCA.bks:设备校验平台身份的证书,用于设备侧接入物联网平台登录鉴权使用,可以在资源获取中下载证书文件
    SSLContext sslContext = SSLContext.getInstance("SSL");
    KeyStore keyStore = KeyStore.getInstance("bks");
    keyStore.load(context.getAssets().open("DigiCertGlobalRootCA.bks"), null);//加载libs目录下的证书
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    sslContext.init(null, trustManagers, new SecureRandom());
    sslSocketFactory = sslContext.getSocketFactory();
  3. MainActivity类提供了设置初始化MqttConnectOptions的方法。mqtt连接心跳时间的建议值是120秒,有使用限制
    mqttAndroidClient = new MqttAndroidClient(mContext, serverUrl, clientId);
    private MqttConnectOptions intitMqttConnectOptions(String currentDate) {
        String password = ConnectUtils.sha256_HMAC(editText_mqtt_device_connect_password.getText().toString(), currentDate);
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setCleanSession(true);
        mqttConnectOptions.setKeepAliveInterval(120);
        mqttConnectOptions.setConnectionTimeout(30);
        mqttConnectOptions.setUserName(editText_mqtt_device_connect_deviceId.getText().toString());
        mqttConnectOptions.setPassword(password.toCharArray());
        return mqttConnectOptions;
    }
  4. MainActivity类提供了Mqtt客户端建立连接的的方法connect,并通过回调函数处理连接后的消息返回结果。
    mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener()
    mqttAndroidClient.setCallback(new MqttCallBack4IoTHub());

注:如果连接失败,在initMqttConnects函数中的onFailure回调函数中已实现退避重连,代码样例如下:

@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
	exception.printStackTrace();
	Log.e(TAG, "Fail to connect to: " + exception.getMessage());
	editText_mqtt_log.append("建立连接失败:" + exception.getMessage() + "\n");

	//退避重连
	int lowBound = (int) (defaultBackoff * 0.8);
	int highBound = (int) (defaultBackoff * 1.2);
	long randomBackOff = random.nextInt(highBound - lowBound);
	long backOffWithJitter = (int) (Math.pow(2.0, (double) retryTimes)) * (randomBackOff + lowBound);
	long waitTImeUntilNextRetry = (int) (minBackoff + backOffWithJitter) > maxBackoff ? maxBackoff : (minBackoff + backOffWithJitter);
	try {
		Thread.sleep(waitTImeUntilNextRetry);
	} catch (InterruptedException e) {
		System.out.println("sleep failed, the reason is" + e.getMessage().toString());
	}
	retryTimes++;
	MainActivity.this.initMqttConnects();
}
	

订阅Topic

订阅某Topic的设备才能接收broker发布的关于该Topic的消息,关于平台预置Topic可参考Topic定义

在MainActivity类中提供了订阅命令下发Topic、订阅Topic、取消订阅Topic等功能:

String mqtt_sub_topic_command_json = String.format("$oc/devices/%s/sys/commands/#", editText_mqtt_device_connect_deviceId.getText().toString());
mqttAndroidClient.subscribe(getSubscriptionTopic(), qos, null, new IMqttActionListener()
mqttAndroidClient.unsubscribe(getSubscriptionTopic(), null, new IMqttActionListener()

如果建链成功,可以在回调函数中订阅Topic:

mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
    @Overridepublic void onSuccess(IMqttToken asyncActionToken) {
        ......
        subscribeToTopic();    
}

建链成功后,APP界面日志栏显示如下信息:

属性上报

属性上报是指设备主动向平台上报自己的属性。更多接口信息请参考设备属性上报

在MainActivity类中实现了属性上报Topic、属性上报功能。

String mqtt_report_topic_json = String.format("$oc/devices/%s/sys/properties/report", editText_mqtt_device_connect_deviceId.getText().toString());
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setPayload(publishMessage.getBytes());
mqttAndroidClient.publish(publishTopic, mqttMessage);

设备上报属性成功后可在设备详情页面查看到上报的属性

图1 查看上报数据-PeriodicalReportConfig
图2 查看上报数据-Battery_level

如果在“设备详情”页面没有最新上报数据,请确认设备上报的服务/属性和产品模型中的服务/属性一致。

接收下发命令

在MainActivity类中提供了接收平台下发命令的功能,在MQTT建链完成后,可以在管理控制台设备详情中命令下发或使用应用侧Demo对该设备ID进行命令下发,例如下发参数名为command,参数值为5的命令,下发成功后,在MQTT的回调函数中接收到。

private final class MqttCallBack4IoTHub implements MqttCallbackExtended {
    ......
    @Overridepublic void messageArrived(String topic, MqttMessage message) throws Exception {
        Log.i(TAG, "Incoming message: " + new String(message.getPayload(), StandardCharsets.UTF_8));
        editText_mqtt_log.append("MQTT接收下发命令成功:" + message + "\n");
    }

在设备详情页面可以查看到命令下发状态,这里显示timeout是因为该Demo示例中仅演示接收命令,没有回复响应给平台。

属性上报和命令接收成功,APP界面显示如下: