MQTT的简单介绍
MQTT是广泛应用于物联网的传输协议,基于TCP
MQTT有一个代理服务器,其客户端可以订阅主题或向一个主题发送消息,从而实现通信
MQTT 设计了 3 个 QoS 等级。
- QoS 0:消息最多传递一次,如果当时客户端不可用,则会丢失该消息。
- QoS 1:消息传递至少 1 次。
- QoS 2:消息仅传送一次。
MQTT依赖
在Android中使用MQTT需要引入以下依赖:
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
但是,这些依赖只支持SDK31(Android 11)及以下的系统,因此我们需要修改:
android{
...
compileSdk 31
defaultConfig{
...
targetSdk 31
...
}
}
另外,高版本的core-ktx依赖不支持33及以下的SDK,因此我们需要修改它的依赖:
implementation 'androidx.core:core-ktx:1.0.0'
而且,这些MQTT的依赖不支持AndroidX,因此需要在gradle.properties下增加以下配置:
android.enableJetifier=true
我们也可以使用国内镜像源加速构建,新版本的Android studio需要在settings.gradle修改配置:
pluginManagement {
repositories {
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://repo.huaweicloud.com/repository/maven' }
maven { allowInsecureProtocol = true
url 'http://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
maven { url "https://jitpack.io" }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://repo.huaweicloud.com/repository/maven' }
maven { allowInsecureProtocol = true
url 'http://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
maven { url "https://jitpack.io" }
}
}
当然,我们需要申请权限并注册服务:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
...
<service android:name="org.eclipse.paho.android.service.MqttService" />
...
MQTT的基本使用
要使用MQTT,需要先创建一个MQTT客户端对象:
val url = "tcp://192.168.1.11:1883"
val clientId = "app"
val mqttClient = MqttAndroidClient(this, url, clientId)
MqttAndroidClient对象创建时接收三个参数,按照顺序,功能如下:
- 当前的上下文(this),
- 服务器的url,注意使用tcp协议,
- 客户端的id,一般应保证其是唯一的
想要连接到服务器,需要配置参数,通过MqttConnectOptions对象:
val option = MqttConnectOptions()
option.userName = "test"
option.password = "123456".toCharArray()
在连接服务器之前,需要设置mqttClient的回调:
mqttClient.setCallback(object :MqttCallback{
override fun connectionLost(cause: Throwable?) {
// 连接丢失
}
override fun messageArrived(topic: String?, message: MqttMessage?) {
// 收到信息
}
override fun deliveryComplete(token: IMqttDeliveryToken?) {
// 消息发送完成
}
})
接下来调用mqttClient.connect方法连接到服务器:
mqttClient.connect(option, null, object :IMqttActionListener{
override fun onSuccess(asyncActionToken: IMqttToken?) {
// 成功
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
// 失败
}
})
connect接收三个参数,按照顺序,功能如下:
- 配置参数(刚刚创建的)
- 一个上下文,用于将上下文传递给回调,如不需要则设置为null
- 一个IMqttActionListener,回调
注意,只有订阅后的主题才能被接收,我们需要在connect的回调下订阅主题,或确保已经连接成功后再订阅主题,采用mqttClient的subscribe方法:
mqttClient.connect(option, null, object :IMqttActionListener{
override fun onSuccess(asyncActionToken: IMqttToken?) {
mqttClient.subscribe("Topic", 0)
}
...
})
subscribe方法接收两个参数,第一个参数是主题的名称,第二个参数是Qos
要发送消息,可以通过publish方法,同样需要在connect的回调下发送消息,或确保已经连接成功后再发送消息:
mqttClient.publish("Topic", MqttMessage("Hello World".toByteArray()))
publish接收两个参数,第一个参数是主题的名称,第二个参数是MqttMessage对象
完整代码如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val url = "tcp://192.168.1.11:1883"
val clientId = "app"
val mqttClient = MqttAndroidClient(this, url, clientId)
val option = MqttConnectOptions()
option.userName = "test"
option.password = "123456".toCharArray()
mqttClient.setCallback(object :MqttCallback{
override fun connectionLost(cause: Throwable?) {
// 连接丢失
cause?.printStackTrace()
}
override fun messageArrived(topic: String?, message: MqttMessage?) {
Log.d("message", "messageArrived: $message")
}
override fun deliveryComplete(token: IMqttDeliveryToken?) {
// 消息发送完成
}
})
mqttClient.connect(option, null, object :IMqttActionListener{
override fun onSuccess(asyncActionToken: IMqttToken?) {
mqttClient.subscribe("Topic", 0)
mqttClient.publish("Topic", MqttMessage("Hello World".toByteArray()))
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
// 失败
exception?.printStackTrace()
}
})
}
}
使用MQTT的测试工具订阅主题Topic,收到消息:
使用MQTT的测试工具向主题"Topic"发送Hello Android,控制台输出:
D/message: messageArrived: Hello Android
可以看到,我们成功地使用了MQTT