简介:面向App Inventor开发者和物联网初学者,这份UrsAI2Paho扩展包是基于Eclipse Paho的MQTT插件,可将Android应用快速接入MQTT服务器,实现设备间消息的发布与订阅。包内共139个文件,以Java源码、properties配置、aia示例工程及aix插件包为主,另有bks、cer、crt、p12等证书文件,用于支持SSL/TLS加密连接,适配智能家居、环境监测等需要安全通信的场景。压缩包约2.16MB,已有604人学习下载。借助内置示例工程与插件源码,使用者可以掌握连接配置、主题订阅、QoS等级设置、心跳维持以及证书安全机制,适合需要快速将App Inventor应用接入物联网的开发者,也适合作为物联网通信原理的学习素材。
1. 为什么装上 UrsAI2Paho 扩展包之后,消息还是不通
做物联项目的人在 AI2 环境里,最后多半会碰到同一个需求:让手机应用和设备之间走 MQTT。APP Inventor UrsAI2Paho扩展包就是把 Paho 的 MQTT 客户端能力封装成可视组件的插件扩展,装完之后连接、订阅、发布、回调全部暴露成积木,不用在 Android 工程里手写协议代码。扩展文件本身不大,真正卡人的是导入之后的事:Broker 地址写错一格就超时,订阅时机不对消息就不来,打包时少带一个组件,装到手机上就静默失败。这篇按我实际装过一遍的顺序来写,从文件格式、Broker 选型、导入步骤、参数配置到打包验证,一条路走完。适合正在做设备远程控制、数据上报,或者已经把扩展丢进项目但还没跑通连接的人。
2. 装前准备:清点环境再动手,扩展与 Broker 各就各位
装扩展之前,先把要用的东西和网络拓扑理清楚,否则装完照样连不上。我一般先做三件事:确认扩展文件是标准 .aix 格式,确认 Broker 监听在哪个地址,确认手机和 Broker 在同一张网里。每一步翻车都有对应的玄学现象,但根因基本都是这三件事没落实。
2.1 文件格式确认:.aix 是 AI2 环境的标准扩展格式
AI2 环境能识别的扩展格式是 .aix,本质上是一个包里装着组件描述和代码的插件文件。拿到 UrsAI2Paho 扩展包之后,第一件事不是双击打开,而是看一眼文件后缀名是不是 .aix,有没有被浏览器多加了后缀或者被系统改掉。
常见做法是把文件放到一个纯英文路径下,比如D:\aix\UrsAI2Paho.aix,文件名也改成全小写加下划线。路径里带中文或空格时,不同改版的 AI2 环境在导入时表现不一致:有的直接报格式错,有的导入后组件面板里什么都看不到。后者最坑,因为界面没有任何报错,你还会以为是扩展本身坏了。
另外,.aix 不要手动解压。有的下载工具会把 .aix 识别成压缩包并自动解压,解压后那一堆散文件没法直接导入,得重新打包成 .aix 才能用。判断方法很简单:文件图标如果显示成文件夹形态,多半已经被解压了,重新下载一份放到干净目录里就好。
2.2 Broker 地址怎么定:先确认它在监听 0.0.0.0 而不是 127.0.0.1
扩展本身不管 Broker 部署在哪里,它只按你填的地址去连。本地测试时,很多人会在电脑上起一个 MQTT Broker,然后把地址填成localhost或127.0.0.1,结果手机应用永远连不上。原因很直接:手机访问的是电脑的局域网 IP,而127.0.0.1是电脑自己的回环口,Broker 只在本机等着,手机的消息根本进不来。
所以配置前先上 Broker 所在的电脑看一眼监听端口。Linux 上用这条命令确认:
# 查看 1883 端口的监听地址,确认不是只绑定在 127.0.0.1 netstat -tlnp | grep 1883如果输出里监听地址是0.0.0.0:1883,说明 Broker 对局域网开放,正常;如果看到的是127.0.0.1:1883,说明 Broker 只在本机回环口上等待,需要去 Broker 配置文件里把 bind 地址改成0.0.0.0再重启。这一步是最容易忽略的局域网部署坑,比防火墙更隐蔽——端口明明通了,但绑定地址不对,外部设备照样连不上。
公共测试 Broker 没有这个问题,因为它对公网开放,只要手机有网就能连。但公共 Broker 不稳定,高峰期掉线、限连都是正常的,适合功能验证,不适合正式项目长期挂着。
2.3 网络路径检查:手机和 Broker 必须在同一张可达的网里
设备连不上 Broker,经常不是扩展的问题,而是手机和 Broker 之间网络根本不通。最经典的场景:电脑连着公司有线网,手机连着公司访客 Wi-Fi,两个网络之间做了 AP 隔离,手机能上网但访问不了电脑。这时候不管你 Broker 配置多正确,连接永远是超时。
我一般会先做一个最朴素的检查:手机浏览器直接打开http://电脑局域网IP:1883,比如http://192.168.1.100:1883。虽然 MQTT 不是 HTTP 协议,浏览器会显示无法访问,但只要网络路径是通的,端口探测会有明显不同的响应表现;如果直接转圈超时,多半是网络隔离或防火墙在拦。
对比法更直接:把手机 Wi-Fi 切到和电脑同一个路由器下,再跑一次连接。如果切换网络后能连上,那就是网络拓扑问题,不是扩展问题。家庭路由器默认设备间互通,但开了“AP 隔离”或“访客网络”后,设备间就互相看不见了,这个开关经常被人无意打开。
2.4 端口与防火墙:1883 需要从手机到 Broker 双向可达
MQTT 默认走 TCP 1883,扩展填的地址里带不带端口直接影响连接目标。如果 Broker 跑在自定义端口,比如 18883,初始化参数里必须写全tcp://192.168.1.100:18883。只写地址不写端口,扩展会去连默认的 1883,端口对不上,报错也是超时。
电脑上的防火墙也可能挡掉入站连接。Linux 上检查放行情况:
# 检查防火墙是否放行 1883 端口 sudo firewall-cmd --list-ports | grep 1883 # 如果没有输出,放行 1883 sudo firewall-cmd --permanent --add-port=1883/tcp && sudo firewall-cmd --reloadWindows 上的做法是到“高级安全 Windows Defender 防火墙”里加一条入站规则,放行 TCP 1883。这里有一个容易翻车的点:如果 Broker 本身只绑定了127.0.0.1,就算防火墙全开也连不上;如果防火墙拦了,Broker 监听0.0.0.0也没用。两个条件必须同时满足。
3. 导入 UrsAI2Paho:菜单入口、组件落位与打包生效
环境准备好之后,就可以把扩展文件导进 AI2 项目了。这一步表面上是“选文件、等提示、拖组件”三连,但不同改版的 AI2 环境在菜单位置上略有差别,导入成功后组件也不会自动出现在屏幕上,加上打包时扩展是否真的进 APK 也不直观,所以单独拿出来讲。
3.1 导入入口与格式校验:在项目页找到 Import extension 按钮
标准 AI2 环境的导入入口在项目设计页里:打开任意一个项目后,菜单栏找到Projects,下拉里有Import extension (.aix),点击后弹出文件选择框。部分改版环境把这个入口挪到了Utilities菜单下,或者项目页右侧的按钮区,但按钮文案基本都是包含 “Import extension” 的关键词。
选择文件后,页面会在顶部短暂出现一个进度提示,导入完成后不会有弹窗提醒,而是直接在左侧组件面板里出现一个新分类EXTENSIONS,展开后能看到UrsAI2Paho组件。如果等了很久还是没出现这个分类,优先怀疑文件被浏览器或下载工具动过手脚。用 Chrome 或 Edge 重新下载一次,放到纯英文路径,再次导入,大多数情况下能解决。
导入完成后注意不要急着打包,先确认扩展组件真的出现在组件面板里。有些环境导入时要求项目处于可编辑状态,项目还在加载中就去点导入,会出现静默失败。
3.2 把扩展拖到画布上:非可视组件的正确落位方式
在组件面板的EXTENSIONS分类下找到UrsAI2Paho,把它拖到设计页的任意位置。这个组件属于非可视组件,拖入后屏幕上不会出现任何控件图标,只有中间那个“非可视组件”区域里多出一行条目。很多新人在这一步以为自己没拖成功,又拖了一次,结果项目里出现两份同名组件,反而把逻辑搞乱。
拖入之后第一件事是重命名。默认名字带数字后缀,比如UrsAI2Paho1,在积木区写逻辑时越长越容易看错。我习惯把它改成MQTT1或Broker1这种短名字,块引用时一眼就能认出是哪个对象。改名的位置在设计页右侧属性面板最上方的Rename按钮,改完之后积木区所有对旧名的引用会自动替换。
顺带说一句,这个扩展在项目里通常只有一个实例。同一个页面里放两个 UrsAI2Paho 组件,各自维护一条 MQTT 连接,逻辑会变得极其绕,而且连接状态回调要区分来源,排查起来非常费劲。对一个简单项目来说,一个连接实例足够。
3.3 打包前检查:项目名、组件存在性和 APK 体积
扩展导入成功只是第一步,APK 打包时扩展有没有被真正包含进去,才是决定“装到手机能不能用”的关键。AI2 项目在打包时会根据界面上的组件清单来决定打进哪些代码,如果一个扩展组件被拖进画布后又删掉了,那这次打包出来的 APK 里就没有这个扩展的任何代码。
所以打包前我一般做三个检查。第一,项目名用英文,不要用中文。AI2 对中文项目名在不同版本上表现不稳定,有人能正常打包,有人卡在打包进度条,还有人打包成功但安装后闪退,为了不赌运气,新建项目时直接用英文命名。第二,去设计页的非可视组件区域确认MQTT1还在,并且没有被误删。第三,看打包完成后 APK 的体积,一个包含 MQTT 扩展的项目,APK 会比空白项目大几百 KB,如果 APK 大小和空项目几乎一样,基本可以断定扩展没被打进去。
这里额外提醒一点:AI2 的打包产物要在浏览器里等它生成,期间不要关闭标签页。打包突然失败时,优先重新生成,而不是反复改代码后直接再打包——好几次“装了扩展打包就失败”的问题,最后发现是浏览器缓存或网络问题,重新打包一次就好了。
4. 配置连接参数:Broker 地址、端口与 Client ID 的取舍
扩展导入项目后,真正的重头戏是配置连接参数。UrsAI2Paho 的初始化积木会要求填一串参数:Broker 地址、端口、客户端 ID、用户名、密码、保活时间、会话清理开关。每一项填错都可能导致不同的故障表现,而这些表现往往都不是直接报“参数错误”,而是连接超时、频繁掉线、消息收不到。
4.1 初始化块参数拆解:tcp:// 前缀必须保留
初始化积木本质上是在创建 MQTT 客户端的连接配置,和 Paho 客户端的new MqttClient()是一回事。我一般这样填:
UrsAI2Paho1.Initialize( broker = "tcp://192.168.1.100:1883", clientId = "mqtt_ai2_01", username = "", password = "", keepAlive = 60, cleanSession = true )broker这个参数必须写全tcp://前缀。它告诉扩展底层走的是 TCP 协议栈,不是 HTTP。192.168.1.100:1883只是地址加端口,不写协议头的时候,有些扩展会默认补上,有些则直接解析失败,返回一个格式错误的事件。为了避免行为不统一,每次我都手动把tcp://带上。
clientId是客户端在 Broker 上的唯一标识,同一时刻同一个 Broker 上不允许两个相同 ID 的客户端共存。测试时图省事,可能所有手机都填同一个clientId,结果就是后连接的手机会把先连接的手机踢下线,表现成 A 手机刚连上,B 手机一连接,A 就弹出断开事件。调试时我习惯在 ID 后面拼上设备区分,比如mqtt_ai2_phone1和mqtt_ai2_phone2。
4.2 用户名密码与 KeepAlive:按连接场景决定参数取舍
用户名和密码在匿名公共 Broker 上可以留空,但留空不意味着没有鉴权。公共 Broker 通常允许匿名连接,只是所有客户端都共享同一个通道,主题之间互相能看到消息内容。测试没问题,正式场景还是建议用带鉴权的 Broker,这样至少能挡住一部分乱连的设备。
KeepAlive 参数控制的是客户端和 Broker 之间的心跳间隔。我一般设 60 秒,也就是 60 秒内没有数据交互,客户端就发一个心跳包告诉 Broker“我还活着”。这个值不能设得太大,比如 300 秒,网络断了之后 Broker 要等 5 分钟才会判定这个客户端离线,期间消息会一直投递失败;设得太小,比如 10 秒,又会增加无线网络下的功耗和流量。对手机端应用来说,60 秒是多数场景下的平衡点。
Clean Session 这个开关要结合业务来选。填true时,Broker 不保存这个客户端的会话状态,重连后之前的订阅全部消失,需要重新订阅;填false时,Broker 会保留订阅关系和未确认消息,适合希望断线重连后还能收到离线消息的场景。我在做设备控制类项目时一般填false,避免网络抖动重连后订阅丢失;做纯上报类项目时填true更省心。
4.3 订阅主题与回调事件:时机、QoS 和消息到达顺序
订阅操作要放在连接成功事件之后,不能放在 Initialize 后面直接执行。原因很简单:TCP 连接还没建立,订阅请求发出去也到不了 Broker。正确顺序是让 UrsAI2Paho 触发Connected事件后,在事件处理积木里执行Subscribe,这样才能保证订阅请求在连接建立后被发送。
订阅时主题格式要用标准 MQTT 风格,比如device/phone1/data,层级用斜杠分隔。通配符+匹配单层,#匹配多层,但通配符不能乱用:device/+/data能匹配device/phone1/data,而device/#会匹配device/下的所有层级。主题大小写敏感,Device/Phone1和device/phone1是完全不同的主题,发布端和订阅端只要大小写不一致,消息就不来,且没有任何提示。
QoS 级别也要在订阅时定下来。QoS 0 走完即焚,网络抖动就会丢;QoS 1 保证 Broker 至少收到一次,可能重复;QoS 2 保证恰好一次,但在弱网下开销较大。手机端项目我订阅时一般用 QoS 1,发布端也保持和订阅端一致。消息到达后,MessageArrived回调里拿到的是字节数组,中文内容需要转成 UTF-8 字符串再处理,否则日志里会看到乱码。
5. 避坑排查:导入失败、超时、掉线与收不到消息
不管前面配置多仔细,实跑的时候还是会撞到几个经典问题。这一章我把 AI2 环境下用 UrsAI2Paho 最常遇到的四类现象整理出来,每条按现象、原因、解决的顺序写。排查时先对照现象定位到对应条目,再按里面的步骤操作,能省掉大量试错时间。
5.1 现象一:导入后组件面板里找不到 UrsAI2Paho
导入过程没有任何报错提示,但左侧组件面板里就是没有EXTENSIONS分类,或者分类有了但里面是空的。有人会反复重导同一份文件,结果还是一样。
原因基本有两种:一是下载文件时浏览器或下载工具动了扩展名,实际得到的不是 .aix 文件;二是导入时项目还在加载中,页面没有处于可编辑状态,导入动作被吞掉了。
解决的办法很机械:先把文件从下载目录移动到纯英文路径,确认后缀确实是.aix。如果文件图标是文件夹样子,说明被解压了,重新下载。然后用 Chrome 无痕窗口打开项目,等项目完全加载完再点导入。我踩过一次 .aix 被下载工具改名的坑,之后每次下载完都会右键看属性确认后缀。
5.2 现象二:连接一直超时,连不上 Broker
初始化之后等不到Connected事件,过一会儿触发连接失败,错误信息是 Connection timeout 或者 Connection refused。这种情况最容易让人怀疑扩展有问题,但绝大多数时候问题在 MQTT 链路本身。
按顺序排查:先在 Broker 电脑上确认监听地址是0.0.0.0而不是127.0.0.1;再确认防火墙放行了 1883 端口;最后确认手机和 Broker 在同一网段且没开 AP 隔离。还有一种情况是 Broker 地址写成了公网域名,但手机网络把该域名或端口封了。我一般先拿电脑上的 MQTT 客户端在同一网络里测一遍,电脑能连而手机不能连,就是手机侧网络问题;两边都不通,就是 Broker 或防火墙的问题。
5.3 现象三:AI2 调试器里能连,打包安装后就超时
这个现象最迷惑:在 AI2 的调试环境里连接正常,编译成 APK 装到手机上就超时。有人会反复重打包,还有人怀疑是扩展不支持打包,其实问题通常出现在地址和项目名上。
调试时连接的 Broker 地址如果填的是localhost或127.0.0.1,调试器环境因为走的是另一层数据通道,可能仍然能通;但 APK 是直接在手机系统上跑的,localhost指的就是手机自己,当然连不到电脑上的 Broker。另外,打包时项目名或路径里的中文也可能导致扩展资源没正确打包,装上去之后缺少连接能力,同样表现为超时。
解决:把 Broker 地址改成电脑的局域网 IP,确保手机和电脑在同一路由器的局域网内,项目名改成纯英文,重新打包一次。装好后先用手机浏览器访问http://电脑IP:1883,确认网络通路正常,再点连接按钮。
5.4 现象四:连接成功后,订阅主题收不到消息
Connected事件触发了,Subscribe也调用成功了,但发布端发消息,AI2 端一直不进MessageArrived回调。这种状态最让人烦躁,因为所有配置看起来都是对的。
先从 Topic 上排查:发布端和订阅端的主题是否完全一致,包括大小写。demo/Phone1和demo/phone1在 MQTT 里是两个不同主题。再看订阅时机:如果 Subscribe 放在 Initialize 后立即执行,TCP 连接没建立,订阅请求丢失了,需要把订阅动作挪到Connected事件里。还有一种情况是 QoS 不匹配:发布端用 QoS 0,弱网环境下 Broker 直接丢弃消息;订阅端用 QoS 2,连接不稳定时重传逻辑复杂,表现为时通时不通。统一用 QoS 1 能减少很多不确定性。
最后确认发布端和订阅端用的是同一台 Broker。本地电脑起了 Broker,同时又拿公共 Broker 地址测试,两个 Broker 之间互不相通,收不到消息是必然的。我在排查时会把 Broker 地址写在一张纸上,逐字核对,避免两个地址太相似看走眼。
6. 验证跑通:外部 MQTT 客户端与 AI2 端做一次发布订阅回环
连接配置完,别急着写业务逻辑,先做一次发布订阅回环验证。所谓回环,就是让 AI2 端和一个外部客户端连到同一个 Broker,互相发一条消息,确认两条方向都通。这一步跑通,才能说 UrsAI2Paho 真正“装好”了。
6.1 准备一个桌面端验证脚本
我习惯在电脑上用 Paho 的 Python 客户端做验证端。先安装依赖:
# 安装 Paho MQTT 的 Python 客户端库 pip install paho-mqtt然后写一段脚本,同时承担发布和订阅两个角色:
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("desktop connected, rc =", rc) # 订阅 AI2 端发来的主题 client.subscribe("demo/ai2_to_desktop", qos=1) def on_message(client, userdata, msg): print("desktop received:", msg.topic, msg.payload.decode('utf-8', errors='ignore')) client = mqtt.Client(client_id="desktop_verify_01") client.username_pw_set("", "") client.on_connect = on_connect client.on_message = on_message # 连接同一台 Broker,地址换成你的实际 IP client.connect("192.168.1.100", 1883, 60) # 发布一条消息到 AI2 端订阅的主题 client.publish("demo/desktop_to_ai2", "hello from desktop", qos=1) client.loop_forever()这段脚本里,桌面客户端订阅了demo/ai2_to_desktop,并向demo/desktop_to_ai2发布消息。AI2 端需要做相反的配置:订阅demo/desktop_to_ai2,发布时发到demo/ai2_to_desktop。注意桌面端的client_id不能和 AI2 端填的一样,否则两个客户端会互相踢下线,回环验证变成掉线验证。
6.2 按清单跑一遍,确认链路通
脚本跑起来后,按下面的顺序验证:
| 步骤 | 操作 | 预期结果 |
|---|---|---|
| 1 | 确认 Broker 端口可达 | 桌面脚本打印connected |
| 2 | AI2 端点击连接 | 数秒内触发Connected事件 |
| 3 | 桌面脚本发布消息 | AI2 端MessageArrived回调触发 |
| 4 | AI2 端向demo/ai2_to_desktop发布消息 | 桌面终端打印收到消息 |
| 5 | 手机断开 Wi-Fi 再重连 | AI2 端自动重连并恢复订阅 |
第 5 步很多人会跳过,但我觉得它是最值得测的。手机网络切换是物联网场景里的常态,如果扩展在重连后不会自动恢复订阅,后续业务逻辑再完整都是白搭。如果 Clean Session 配置了false,这一步基本能顺利通过;如果开的是true,重连后需要在Connected事件里重新执行一次订阅。
这个回环验证最后一次帮我抓到的问题,是 Broker 地址多打了一个空格——肉眼完全看不出来,但 Paho 底层解析时直接报错。从那以后我每次接入新的 MQTT 扩展,都会先让一个外部客户端发一条消息,把往返链路验证完再开始写业务逻辑,希望帮到你。
本文还有配套的精品资源,点击获取