MQTT:适用于IOT环境的轻量级网络框架。
原理:观察者模式,订阅/发布。
场景:阿里云IOT平台。
网络框架,本篇文章只关注Android端(终端)的使用。
参考官方文档:阿里云-微消息队列MQTT
消息发送是订阅推送的形式,终端与云端建立连接,并订阅主题,云端向终端推送消息。
优点是使用方便,资源利用小,支持断线重连和断线缓存,支持TCP也支持SSL连接。缺点的话就是坑比较多,一路坑坑洼洼。
截止目前,阿里云官网上关于Android的文档还没有,可参考java的demo,经测试一样用。文档也不太清晰,关于API基本就是看Demo。
具体说明及服务器端配置详看官方文档,服务器端代码也比较简单,和Android端类似,下面讲述Android端步骤:
1.gradle引入:
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation group: 'commons-codec', name: 'commons-codec', version: '1.5'
其中,第一个是主包;第二个为了适配Android,带有广播服务之类的组件;第三个为了引入SHA1加密等。
2.权限比较良心,没有什么乱七八糟:
3.声明服务:
4.MqttAndroidClient,这里的回调建议设置成订阅消息的回调。以下代码建议放到服务中,start还是bind的方式看业务逻辑,但是记得要在服务destroy的时候断开连接。
mqttAndroidClient = new MqttAndroidClient(MyMqttService.this, NetConstant.BROKER, NetConstant.CLIENT_ID);
mqttAndroidClient.setCallback(new MqttCallback() { //设置监听订阅消息的回调
@Override
public void connectionLost(Throwable cause) {
//连接断开
Log.d(TAG, "connectionLost: 连接丢失");
cause.printStackTrace();
}
@Override
public void messageArrived(String topic, MqttMessage message) {
//订阅的消息送达,推送notify
String payload = new String(message.getPayload());
Log.d(TAG, "Topic: " + topic + " ==> Payload: " + payload);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//即服务器成功delivery消息
Log.d(TAG, "deliveryComplete: ");
}
});
5.设置连接参数,这块参数问后台要。clientId是识别到此设备的id,要和后台统一规则,并且后台设置是全部推送还是定向。在这里我们用签名鉴权方式,网上大部分都是用的token鉴权。签名鉴权阿里云的这个需要用到加密工具,都可以从阿里云的demo中拿到。
/**
* 计算签名,将签名作为MQTT的password。
* 签名的计算方法,参考工具类MacSignature,第一个参数是ClientID的前半部分,即GroupID
* 第二个参数阿里云的SecretKey
*/
String sign = "";
try {
sign = MacSignature.macSignature(NetConstant.CLIENT_ID, NetConstant.SECRET_KEY);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//新建连接设置
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
//断开后,是否自动连接
mqttConnectOptions.setAutomaticReconnect(true);
//是否清空客户端的连接记录。若为true,则断开后,broker将自动清除该客户端连接信息
mqttConnectOptions.setCleanSession(false);
//设置超时时间,单位为秒
//mqttConnectOptions.setConnectionTimeout(60);
//心跳时间,单位为秒。即多长时间确认一次Client端是否在线
mqttConnectOptions.setKeepAliveInterval(60);
//允许同时发送几条消息(未收到broker确认信息)
//mqttConnectOptions.setMaxInflight(10);
//选择MQTT版本
mqttConnectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
mqttConnectOptions.setUserName("Signature|" + NetConstant.ACESS_KEY + "|" + NetConstant.INSTANCE_ID);
mqttConnectOptions.setPassword(sign.toCharArray());
mqttConnectOptions.setServerURIs(new String[]{NetConstant.BROKER});
6.连接并监听回调
try {
//开始连接
mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "onSuccess: Success to connect to 连接成功 " + NetConstant.BROKER);
DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
disconnectedBufferOptions.setBufferEnabled(true);
disconnectedBufferOptions.setBufferSize(100);
disconnectedBufferOptions.setPersistBuffer(false);
disconnectedBufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
//成功连接以后开始订阅
subscribeAllTopics();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//连接失败
Log.d(TAG, "onFailure: Failed to connect to 连接失败 " + NetConstant.BROKER);
exception.printStackTrace();
}
});
} catch (MqttException ex) {
ex.printStackTrace();
}
7.订阅服务
/**
* 订阅消息
*/
public void subscribeToTopic(String subscriptionTopic) {
try {
mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "onSuccess: Success to Subscribed!");
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(TAG, "onFailure: " + exception.getCause());
Log.d(TAG, "onFailure: Failed to subscribe " + exception.getMessage());
exception.printStackTrace();
}
});
} catch (MqttException ex) {
Log.d(TAG, "subscribeToTopic: Exception whilst subscribing");
ex.printStackTrace();
}
}
8.发布消息
/**
* 发布消息
*/
public void publishMessage(String msg) {
try {
MqttMessage message = new MqttMessage();
message.setPayload(msg.getBytes());
// 参数topic:发布消息的主题
// 参数payload:消息的字节数组
// 参数qos:提供消息的服务质量,可传0、1或2
// 参数retained:是否在服务器保留断开连接后的最后一条消息
mqttAndroidClient.publish(IOT_TOPIC, message);
Log.d(TAG, "publishMessage: Message Published: " + msg);
} catch (MqttException e) {
Log.d(TAG, "publishMessage: Error Publishing: " + e.getMessage());
e.printStackTrace();
}
}
整体代码可以从git上下载学习:MQTTDemo
关于Android-SDK使用的git:MQTT-SDK源码