蓝牙低功耗扫描仪
一款用于浏览蓝牙低功耗外围设备内容的应用程序。该示例演示了如何使用所有 Qt Bluetooth 低功耗类的方法。
“蓝牙低功耗扫描器”示例展示了如何使用 Qt Bluetooth API开发蓝牙低功耗应用程序。该应用程序涵盖了扫描低功耗设备、扫描其服务以及读取服务特征和描述符等功能。

该示例介绍了以下 Qt 类:
该示例可与任意蓝牙低功耗外设配合使用。它会生成所有服务、特征和描述符的快照,并将其呈现给用户。因此,该应用程序提供了一种便捷的方式,用于浏览外设提供的内容。
运行示例
您可以从以下位置运行该示例:
- Qt Creator
打开Welcome 模式,并从Examples 中选择该示例。有关更多信息,请参阅Qt Creator :教程:构建和运行。
- Qt Extension for Visual Studio Code
在Command Palette 中运行Qt: Open Qt examples 命令,并从列表中选择该示例。有关更多信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
请求使用蓝牙的权限
在某些平台上,必须明确授予使用蓝牙的权限。该示例使用BluetoothPermission QML 对象来检查并请求权限(如有需要):
BluetoothPermission {
id: permission
communicationModes: BluetoothPermission.Access
onStatusChanged: {
if (permission.status === Qt.PermissionStatus.Denied)
Device.update = "Bluetooth permission required"
else if (permission.status === Qt.PermissionStatus.Granted)
devicesPage.toggleDiscovery()
}
}当用户尝试启动设备发现时,会触发权限请求对话框,此时权限状态为Undetermined :
onButtonClick: {
if (permission.status === Qt.PermissionStatus.Undetermined)
permission.request()
else if (permission.status === Qt.PermissionStatus.Granted)
devicesPage.toggleDiscovery()
}如果用户授予了该权限,设备发现将开始;否则,应用程序将无法正常运行。
扫描设备
第一步是查找所有外围设备。可通过QBluetoothDeviceDiscoveryAgent 类查找设备。使用start()方法启动发现过程。每个新设备都会通过deviceDiscovered()信号进行广播:
discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
discoveryAgent->setLowEnergyDiscoveryTimeout(25000);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &Device::addDevice);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred,
this, &Device::deviceScanError);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
this, &Device::deviceScanFinished);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
this, &Device::deviceScanFinished);
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);下方的addDevice() 槽在发现新设备时被触发。它会过滤所有带有QBluetoothDeviceInfo::LowEnergyCoreConfiguration 标志的已发现设备,并将它们添加到一个列表中,供用户查看。随着更多详细信息的发现,同一设备可能会多次发出deviceDiscovered()信号。在此,我们对这些设备发现进行匹配,以便用户仅看到单个设备:
void Device::addDevice(const QBluetoothDeviceInfo &info)
{
if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
auto devInfo = new DeviceInfo(info);
auto it = std::find_if(devices.begin(), devices.end(),
[devInfo](DeviceInfo *dev) {
return devInfo->getAddress() == dev->getAddress();
});
if (it == devices.end()) {
devices.append(devInfo);
} else {
auto oldDev = *it;
*it = devInfo;
delete oldDev;
}
emit devicesUpdated();
}
}设备列表可能如下图所示。
注意: 远程设备必须主动广播其存在状态,这是 必要条件。

连接到服务
用户从列表中选择设备后,应用程序将连接到该设备并扫描所有服务。使用QLowEnergyController 类连接到设备。QLowEnergyController::connectToDevice()函数将触发连接过程,该过程将持续进行,直到接收到QLowEnergyController::connected()信号或发生错误为止:
if (!controller) {
// Connecting signals and slots for connecting to LE services.
controller = QLowEnergyController::createCentral(currentDevice.getDevice(), this);
connect(controller, &QLowEnergyController::connected,
this, &Device::deviceConnected);
connect(controller, &QLowEnergyController::errorOccurred, this, &Device::errorReceived);
connect(controller, &QLowEnergyController::disconnected,
this, &Device::deviceDisconnected);
connect(controller, &QLowEnergyController::serviceDiscovered,
this, &Device::addLowEnergyService);
connect(controller, &QLowEnergyController::discoveryFinished,
this, &Device::serviceScanDone);
}
if (isRandomAddress())
controller->setRemoteAddressType(QLowEnergyController::RandomAddress);
else
controller->setRemoteAddressType(QLowEnergyController::PublicAddress);
controller->connectToDevice();由connected() 信号触发的槽会立即调用QLowEnergyController::discoverServices(),以在已连接的外设上启动服务发现。
controller->discoverServices();生成的列表将呈现给用户。下图显示了选择 SensorTag 设备时的结果。该视图列出了服务的名称、其为主服务还是次要服务,以及用于确定服务类型的 UUID。

一旦选择服务,系统会立即创建相关的QLowEnergyService 实例,以便与该服务进行交互:
QLowEnergyService*service = controller->createServiceObject(serviceUuid);
if(!service) {
qWarning() << "Cannot create service for uuid";
return;
}该服务对象提供了必要的信号和函数,用于获取服务详情、读写特性与描述符,以及接收数据变更通知。 数据变更通知可能由值写入操作触发,也可能由设备内部逻辑引发的设备端更新触发。在初始详细信息搜索过程中,该服务的state()状态会从RemoteService 过渡到RemoteServiceDiscovering ,最终结束于RemoteServiceDiscovered :
connect(service, &QLowEnergyService::stateChanged,
this, &Device::serviceDetailsDiscovered);
service->discoverDetails();
setUpdate(u"Back\n(Discovering details...)"_s);读取服务数据
选择某项服务后,将显示该服务的详细信息。每个特征都会与其名称、UUID、值、句柄及属性一同列出。

可以通过QLowEnergyService::characteristics()获取该服务的特征,进而可以通过QLowEnergyCharacteristic::descriptors()获取每个描述符。
const QList<QLowEnergyCharacteristic> chars = service->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
auto cInfo = new CharacteristicInfo(ch);
m_characteristics.append(cInfo);
}尽管示例应用程序不会显示描述符,但当无法根据 UUID 识别特征名称时,它会使用描述符来获取该特征的名称。获取名称的第二种方法是检查是否存在类型为QBluetoothUuid::DescriptorType::CharacteristicUserDescription 的描述符。以下代码演示了如何实现这一点:
QString name = m_characteristic.name();
if (!name.isEmpty())
return name;
// find descriptor with CharacteristicUserDescription
const QList<QLowEnergyDescriptor> descriptors = m_characteristic.descriptors();
for (const QLowEnergyDescriptor &descriptor : descriptors) {
if (descriptor.type() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) {
name = descriptor.value();
break;
}
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.