Go 语言蓝牙通信关键在于选库和运行平台:Linux/macOS 可用 gatt 或 currantlabs/ble,Windows 基本不可行;Linux 需 BlueZ ≥5.50、启用服务、用户加入 bluetooth 组,并注意 MTU 协商、服务注册顺序及权限配置。

Go 语言做蓝牙通信,核心不是“能不能”,而是“用哪个库”和“在哪跑”——Linux/macOS 可以直接上 gatt 或 currantlabs/ble;Windows 基本不可行,别硬刚。
Linux 下用 gatt 启动 BLE 外设服务,必须装 BlueZ 并配好权限
Linux 不是插上蓝牙适配器就能用。gatt 依赖系统级 Bluetooth 协议栈,实际走的是 BlueZ 的 D-Bus 接口或 HCI socket。没装对、没启服务、没加用户组,gatt.NewDevice() 直接 panic 或返回 "no such device"。
- 确认 BlueZ 版本 ≥ 5.50:
bluetoothctl --version,低于就 apt/yum 升级 - 确保
bluetooth服务运行:sudo systemctl start bluetooth,且启用自启 - 当前用户必须加入
bluetooth组:sudo usermod -aG bluetooth $USER,然后重新登录 - 如果用
option.DefaultServerOptions启动失败,试试显式指定适配器:gatt.DeviceOptions{DeviceID: 0}(对应hci0)
扫描设备时用 currantlabs/ble,注意 ble.Scan() 是阻塞的,别漏掉 channel 控制
很多人写完 ble.Scan() 就卡住,程序不退出也不报错——因为默认它会一直扫,直到你关掉 channel。这不是 bug,是设计。不加超时或手动 stop,goroutine 就挂在那里。
- 正确做法是用
context.WithTimeout包一层,或者像示例里那样起 goroutine +time.After关闭 channel -
ble.WithFilter()的回调函数里,adv.LocalName()可能为空,优先看adv.ManufacturerData()或adv.ServiceUUIDs()判断设备类型 - macOS 上扫描正常,但 Linux 下若用 USB 蓝牙狗,某些型号(如 Cambridge Silicon Radio)需加 udev 规则,否则无权限访问 HCI 设备
gatt.CentralConnected 回调里不能直接读特征值,得等 MTU 协商完成
刚连上的 Central 还没完成 ATT MTU Exchange,此时调 c.ReadCharacteristic() 会返回 "attribute not found" 或 timeout。这不是服务没加对,是协议时序问题。
立即学习“go语言免费学习笔记(深入)”;
- 务必监听
gatt.CentralMTUUpdated事件,收到后再发读写请求 - 服务注册顺序有影响:先
d.AddService(service.NewGapService(...)),再加自定义 service,否则某些 central(如 iOS)可能无法发现服务 - 特征值(
Characteristic)的Permissions和Properties必须匹配客户端操作,比如想被读,就得设gatt.PermissionRead且gatt.PropertyRead
跨平台兼容性差是硬伤,别指望一套代码 macOS/Linux/Android 全跑通
macOS 用 XPC,Linux 用 BlueZ D-Bus/HCI,Android 根本没原生 Go BLE 支持——currantlabs/ble 和 gatt 都不支持 Android。有人试过 cgo 调 NDK,但维护成本高、ABI 不稳、权限模型冲突。
- macOS 上
gatt用xpc子模块,无需额外依赖;但调试时要关 SIP 才能看到部分日志 - Linux 上若用
ble.Connect()连不上,先用gatttool -I手动测试,排除硬件或 pairing 问题 - 所有库都不处理 BLE 配对(bonding),加密和密钥分发得自己在应用层补,
gatt的CentralPairingRequest仅提供钩子,不实现逻辑
真正麻烦的从来不是写几行 ReadCharacteristic,而是弄清你面对的是哪一层:HCI 命令是否发出?L2CAP 通道是否建好?ATT 请求有没有被 remote 拒绝?——查日志前,先确认你连的是协议栈哪一层。


















