简介:Android MQTT客户端源码包,面向物联网应用开发者与Android学习人员,提供可直接安装运行的APK与完整工程代码,解决移动端与MQTT消息服务器的快速对接问题。压缩包内共56个文件,涵盖Java源码、class编译文件、XML界面与配置、jar依赖库以及APK安装包等,体积仅1.62MB,便于开发者快速部署与二次开发。已有1473人学习下载,源码围绕MqttAndroidClient核心类展开,详细实现连接建立、主题发布与订阅、消息回调以及异常处理等关键模块;bin目录下的APK可免编译直接安装,libs目录则封装了MQTT协议依赖库,assets与res目录提供应用资源,整体结构清晰适合逐步研读。配套说明推荐结合开源Mosquitto服务端,帮助读者从零搭建端到端的物联网通信演示,既能用于实际项目快速验证,也为深入理解MQTT协议、掌握Android网络编程提供完整参考资料。 最近在做一个设备远程监控的项目,Android 端需要稳定地接收 MQTT 消息。最早我是想找个现成的客户端源码,装上就能用,省得重复造轮子。翻了一圈,要么是 demo 级别只能连公共 broker,要么编译的时候各种报错,真正能直接打包安装的比较少。于是自己基于 Eclipse Paho 整理了一版 Android MQTT 客户端源码,支持订阅、发布、断线重连、TLS 证书配置,在 Android Studio 里打开就能构建 APK,装到手机上就能连 broker 收发消息。
这篇内容就把这套源码的思路、核心代码、编译流程和踩过的坑完整记录下来,给后面做物联网、消息推送、车牌识别相机对接的朋友一个可以直接参考的底子。
1. 源码整体设计与技术选型
1.1 从"能连上"到"能直接装"差多少
市面上很多 MQTT 示例代码,核心逻辑就几行:创建 MqttClient、setCallback、connect、subscribe。在 PC 上跑没问题,但放到 Android 里就完全不是一回事了。
Android 端的 MQTT 客户端要处理的事比想象中多:网络状态变化要自动重连,App 退到后台不能被系统杀掉连接,界面销毁时不能泄漏线程,还有 Android 8 以上对后台服务的限制、Android 12 对 PendingIntent 的 Flag 要求。这些不处理好,所谓"能用的源码"装上就是闪退、永远连不上、或者锁屏后就掉线。
我整理这版源码时,把这些问题都做了处理,保证不是"实验室能跑",而是"真机装上能用"。
1.2 为什么选择 Eclipse Paho
Android 上 MQTT 客户端库主要有 Eclipse Paho、HiveMQ MQTT Client,以及某些云厂商自带 SDK。Paho 是 Eclipse 基金会维护的开源项目,社区活跃、文档全、协议支持完整,而且有专门的 Android Service 版本。
Paho 的 Android Service 封装了连接生命周期,它自己维护一个前台服务来持有 MQTT 连接。这样即使 Activity 销毁了,只要 Service 不被杀掉,连接还能保住。另外它还自动处理网络切换时的重连,这对手机端来说太关键了,毕竟 Wi-Fi 和蜂窝网络切换是家常便饭。
我在源码里用的是两个库:
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'如果你只引入第一个库,也能实现 MQTT 收发,但断线重连、Service 托管这些全要自己写。引入第二个库,就能直接用 MqttAndroidClient,少写很多底层逻辑。
2. 核心模块与关键代码解析
2.1 工程目录与分层
源码按功能分成三层:连接层、业务封装层、UI 层。
连接层负责 MQTT 服务的建立,业务封装层对外提供订阅、发布、消息回调接口,UI 层就是测试页面。结构大概这样:
app/src/main/java/com/example/mqttclient/ ├── MQTTManager.java // 连接管理单例 ├── MQTTService.java // Paho Android Service ├── MqttMessageListener.java // 消息回调接口 ├── activity/ │ └── MainActivity.java // 测试界面 └── util/ └── PreferencesUtil.java // 保存连接配置MQTTService 继承自 Paho 的 MqttService,需要在 AndroidManifest 里注册。这个 Service 是连接的核心载体,所有 MQTT 网络请求都通过它转发。
MQTTManager 是单例,负责创建 MqttAndroidClient、发起连接、订阅主题、发布消息。把它做成单例的好处是,整个 App 任何时候都只需要一个连接实例,不会出现多个连接互相抢占资源的局面。
2.2 连接参数与回调机制
连接参数的设置是重点,直接影响连接稳定性和耗电。源码里默认配置如下:
MqttConnectOptions options = new MqttConnectOptions(); options.setAutomaticReconnect(true); options.setCleanSession(true); options.setKeepAliveInterval(30); options.setConnectionTimeout(10);这几个参数我逐个说下。
setAutomaticReconnect(true)让 SDK 在网络恢复时自动重连,不需要自己监听 ConnectivityManager。实测下来,Wi-Fi 切 4G 时连接基本能在 10 秒内恢复。
setCleanSession(true)表示每次连接都是全新会话,不保留离线消息。如果你需要离线消息,要设成 false,并且订阅时要设置 QoS 为 1 或 2,同时 broker 端要保留消息。这个要根据业务场景来,我的项目用的是临时命令下发,所以 CleanSession 为 true 就够了。
setKeepAliveInterval(30)是心跳间隔,单位秒。Paho 默认 60 秒,但移动网络下运营商 NAT 超时时间通常只有 30 秒左右,设太长了会被服务端判定掉线。设成 30 秒比较均衡。
setConnectionTimeout(10)是连接超时时间。这个不能太小,否则弱网环境容易连不上。
回调方面,Paho 的 MqttCallback 提供了连接丢失、消息到达、发送完成三个方法。源码里把这三个方法封装成 MqttMessageListener,业务层只管实现接口就行。
public interface MqttMessageListener { void onConnected(); void onDisconnected(); void onMessageReceived(String topic, String payload); }这样写的好处是,UI 层不直接依赖 Paho 库,以后想换别的 MQTT 库,只要改 MQTTManager 内部实现,页面代码不用动。
2.3 订阅与发布的细节处理
订阅主题时,我建议不要写死 topic,而是从 SharedPreferences 里读取,这样换 broker、换项目不用改代码重新打包。源码里提供了一个简单的配置页,输入 broker 地址、端口、用户名、密码、订阅主题,保存后下次启动自动加载。
发布消息时有个容易踩的坑:Paho 的 publish 方法默认 QoS 为 0,消息可能丢失。如果是控制指令,建议至少用 QoS 1,能保证消息至少到达一次。
MqttMessage message = new MqttMessage(payload.getBytes()); message.setQos(1); mqttAndroidClient.publish(topic, message);同时注意,publish 不能放在主线程里,否则可能触发 NetworkOnMainThreadException。源码里用了一个单线程 Executor 来执行发布操作,避免阻塞 UI。
3. 从源码到安装包:编译与部署流程
3.1 Android Studio 环境准备
我用的开发环境是 Android Studio Hedgehog 2023.1.1,Gradle 版本 8.2,AGP 版本 8.2.2。这套源码的 compileSdk 是 34,minSdk 是 21。如果你用的版本偏老,至少要保证 compileSdk 不低于 33,否则 Paho Android Service 的一些 API 会编译不过。
导入工程时,直接用 Android Studio 的Open选择项目根目录,等待 Gradle Sync 完成。如果同步报错,先检查 Gradle JDK 版本,建议用 17。
3.2 AndroidManifest 配置要点
Paho 的 Android Service 需要在 Manifest 里注册,并且 Android 12(API 31)以上必须声明android:exported。
<service android:name="org.eclipse.paho.android.service.MqttService" />网络权限和唤醒锁权限也得加:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" />ACCESS_NETWORK_STATE 是用来监听网络变化的,不加的话自动重连功能可能会失效。WAKE_LOCK 是防止设备休眠时连接断开,如果你不想 App 在后台耗电,可以不用,但连接稳定性会差一些。
3.3 生成 APK 并安装
配置好之后,Build 菜单选择Build APK(s),Android Studio 会生成 debug 或 release 包。debug 包默认签名,可以直接安装测试。
我第一次构建时遇到一个问题:打包后安装到 Android 14 手机上,一打开就闪退,logcat 里报PendingIntent mutability异常。这是 Paho 1.1.1 版本在 Android 12 以上的已知问题,需要手动设置 FLAG_IMMUTABLE 或 FLAG_MUTABLE。源码里通过反射修正了这个问题,构建时不用额外处理。
如果你的项目直接使用了原始 Paho 库没做处理,遇到这个闪退可以在调用连接前加上:
Class<?> cls = Class.forName("org.eclipse.paho.android.service.MqttService");然后通过反射找到createConnection或其他相关方法,给 PendingIntent 设置标志。但不同 Android 版本方法名不一样,源码里已经做了兼容处理,所以直接用整理好的版本最省事。
4. 业务场景扩展:从订阅消息到对接设备
4.1 消息格式与 Topic 规划
客户端源码本身只负责消息收发,真正有业务价值的是消息格式约定。以停车场项目中常见的车牌识别相机对接为例,相机通过 MQTT 上报识别结果,Android 客户端订阅识别主题,然后处理图片和车牌号。
实际项目中,Topic 通常按设备维度组织,比如:
plate/device/{deviceId}/recognize:设备上报识别结果plate/device/{deviceId}/status:设备在线状态plate/gate/{gateId}/control:客户端下发开闸指令
这种命名方式的好处是,客户端可以通配符订阅plate/device/+/recognize,一次订阅就能接收所有设备的识别结果,不用为每台设备单独订阅。
4.2 MQTT 与车牌识别相机对接思路
对接海康、大华等主流车牌识别相机时,很多相机自带 MQTT 功能,或者支持通过协议转换网关转发。Android 客户端只需要按约定 Topic 订阅即可。
比如相机识别到车牌后,会往plate/device/{deviceId}/recognize发布一条 JSON:
{ "deviceId": "HIK-001", "plateNumber": "粤B12345", "timestamp": 1731234567890, "imageUrl": "http://192.168.1.64/snapshot/xxx.jpg" }客户端收到后解析 JSON,在页面上弹出车辆信息,然后根据后端逻辑决定是否下发开闸指令。这个过程中,MQTT 客户端只做传输层,具体业务规则全部由业务层处理。
这套源码里预留了消息解析的接口,收到的 payload 会以 String 形式回调出去,你可以在 onMessageReceived 里用 JSONObject 解析,或者直接接入 Gson。
4.3 断线重连与消息补拉
虽然 Paho 的 automatic reconnect 能恢复连接,但断线期间的消息会丢失。如果业务要求严格,需要配合 broker 端的持久会话(CleanSession=false)+ QoS1 来保证。不过这样也有副作用,broker 会为客户端缓存消息,如果客户端一直不在线,积压消息会占内存。
在 Android 端,我更推荐断线后主动拉取一次未读消息,比如通过 HTTP 接口查询设备离线期间的状态。MQTT 只做实时通知,不承担可靠存储的职责。这也是我在项目里实际采用的做法,简单可靠,省去排查消息错乱的麻烦。
5. 常见问题与避坑清单
5.1 编译期问题
问题:Java 8 语法不支持
Paho 最新版需要 Java 8,如果报Default method或Lambda expressions are not supported,在 app 的 build.gradle 里加上:
compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }问题:MqttService 找不到
确认 Manifest 里注册的 Service 类名是否完整,Paho 的类在org.eclipse.paho.android.service包下,不要写错。另外,确保依赖里包含org.eclipse.paho.android.service库,而不是只引了 mqttv3。
问题:构建时提示 duplicate class
这种情况通常是你同时引入了 Paho 和其他 MQTT 库,或者重复依赖了 mqttv3。检查依赖树:
./gradlew :app:dependencies如果发现重复依赖,用exclude去掉其中一个即可。
5.2 运行时常见问题
问题:连接成功但收不到消息
先确认订阅主题是否匹配 broker 端的发布主题。MQTT 主题是区分大小写的,Plate/Device和plate/device是两个完全不同主题。其次检查 QoS,如果发布端用 QoS0 且客户端订阅也用 QoS0,消息在网络抖动时可能直接丢弃。
问题:App 切后台一段时间后连接断开
这通常是系统 Doze 模式导致的。Android 6.0 以上,设备进入 Doze 后会禁止网络访问。解决方案有两个:一是把 App 加入电池优化白名单(需要用户手动授权),二是使用 Firebase Cloud Messaging 之类的系统级推送通道来唤醒 App。如果只是开发测试,用前台服务 + WAKE_LOCK 可以明显改善,但无法完全绕过 Doze。
问题:连接被服务端踢掉,日志提示 "Already connected"
这往往是客户端没有正确关闭旧连接,又重新发起连接导致的。Paho 在connect之前,最好先检查isConnected(),如果已连接,先disconnect()再连接,或者直接复用现有连接。源码里已经加了这个判断,避免重复连接。
5.3 耗电与性能优化
MQTT 是长连接应用,天然会耗电。实测下来,心跳 30 秒时,一部 5000mAh 的手机待机一晚(8 小时)大概耗电 8% 左右,还算能接受。如果想进一步优化,可以把 KeepAlive 提高到 45 秒或 60 秒,但要做好运营商 NAT 超时的准备。
另外,不要在onMessageReceived里直接做耗时操作,比如下载图片、解析大文件。正确做法是把数据丢到 HandlerThread 或协程里处理,避免阻塞 MQTT 内部线程。Paho 的消息回调是在 Binder 线程池里执行的,阻塞会导致后续消息延迟。
6. 这套源码的可扩展方向
如果你不想只停留在收发消息,这套客户端源码还可以继续扩展:
一是把连接参数做成动态配置,通过扫码或后端接口下发 broker 地址,这样同一个 App 可以对接不同项目,不用每次重新打包。
二是接入 TLS 双向认证。Paho 支持 SSL,在 MqttConnectOptions 里设置 SocketFactory,用 Android 的KeyChain或BKS证书库加载客户端证书。这在企业级项目里很常见,避免了用户名密码被截获的风险。
三是把消息桥接给本地数据库。比如收到设备状态后写入 Room,这样离线时也能查看历史记录。我目前的版本只做了内存回调,如果你有这个需求,在 MqttMessageListener 的实现类里加一层数据库写入就行。
还有一个小技巧:如果你要同时接多个 broker,不要只用一个 MqttAndroidClient 实例,而是用 Map 维护多个连接,每个连接有自己的 topic 前缀。代码结构上可以把 MQTTManager 改成多连接模式,每个连接对应一个独立的回调监听器。
这套源码最大的价值不是代码量,而是把连接管理、生命周期、重连机制这些 Android 端最容易出错的部分都处理好了,拿来就能跑。后面即使要扩展功能,也只需要在业务层加代码,不需要动底层。实际用的时候,建议先用公共测试 broker 跑通全流程,再切换到自己部署的 broker,这样排查问题会快很多。
本文还有配套的精品资源,点击获取