Rust蓝牙低功耗(BLE)开发库btleplug的使用,支持跨平台蓝牙设备通信与管理
Rust蓝牙低功耗(BLE)开发库btleplug的使用,支持跨平台蓝牙设备通信与管理
btleplug是一个异步Rust BLE库,支持Windows 10、macOS、Linux、iOS和Android平台。
平台状态
- Linux/Windows/macOS/iOS/Android
- 设备枚举和特性/服务已实现并正常工作
- 如果发现问题请提交bug
平台功能表
功能 | Windows | MacOS/iOS | Linux | Android |
---|---|---|---|---|
启动适配器 | ✔️ | ✔️ | ✔️ | ✔️ |
发现设备 | ✔️ | ✔️ | ✔️ | ✔️ |
发现服务 | ✔️ | ✔️ | ✔️ | ✔️ |
发现特性 | ✔️ | ✔️ | ✔️ | ✔️ |
GATT服务器连接 | ✔️ | ✔️ | ✔️ | ✔️ |
写入特性 | ✔️ | ✔️ | ✔️ | ✔️ |
读取特性 | ✔️ | ✔️ | ✔️ | ✔️ |
订阅特性 | ✔️ | ✔️ | ✔️ | ✔️ |
库特性
序列化/反序列化
启用serde的Serialize
和Deserialize
支持:
[dependencies]
btleplug = { version = "0.11", features = ["serde"] }
完整示例代码
以下是一个更完整的BLE设备交互示例,包含设备连接、服务发现和特性读写操作:
use btleplug::api::{Central, CentralEvent, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;
use futures::stream::StreamExt;
use std::error::Error;
use tokio::time;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// 1. 初始化BLE管理器
let manager = Manager::new().await?;
// 2. 获取第一个蓝牙适配器
let adapter_list = manager.adapters().await?;
let adapter = adapter_list.into_iter().next().ok_or("没有可用的蓝牙适配器")?;
// 3. 开始扫描设备
println!("开始扫描BLE设备...");
adapter.start_scan(ScanFilter::default()).await?;
// 4. 监听设备事件
let mut events = adapter.events().await?;
let mut target_peripheral = None;
while let Some(event) = events.next().await {
match event {
CentralEvent::DeviceDiscovered(id) => {
println!("发现设备: {:?}", id);
// 这里可以添加设备过滤逻辑
target_peripheral = Some(adapter.peripheral(&id).await?);
break;
}
_ => {}
}
}
// 5. 停止扫描
adapter.stop_scan().await?;
println!("扫描停止");
// 6. 连接到目标设备
if let Some(peripheral) = target_peripheral {
println!("尝试连接设备...");
peripheral.connect().await?;
println!("设备已连接");
// 7. 发现服务
println!("发现服务...");
peripheral.discover_services().await?;
let services = peripheral.services();
// 8. 遍历服务和特性
for service in services {
println!("服务: {:?}", service.uuid);
for characteristic in service.characteristics {
println!(" 特性: {:?} - 属性: {:?}",
characteristic.uuid,
characteristic.properties);
// 9. 示例: 读取特性值
if characteristic.properties.read {
let value = peripheral.read(&characteristic).await?;
println!(" 值: {:?}", value);
}
// 10. 示例: 订阅通知
if characteristic.properties.notify {
peripheral.subscribe(&characteristic).await?;
println!(" 已订阅通知");
}
}
}
// 11. 保持连接一段时间
time::sleep(time::Duration::from_secs(10)).await;
// 12. 断开连接
peripheral.disconnect().await?;
println!("设备已断开");
}
Ok(())
}
平台特定说明
macOS
在macOS Big Sur(11)或更高版本上需要:
- 将二进制文件打包到包含
NSBluetoothAlwaysUsageDescription
的应用程序包中 - 或者在系统偏好设置中为终端启用蓝牙权限
Android
Android上的设置步骤:
- 需要jni-utils-rs的Java部分
- 构建btleplug的Java部分
- 使用cargo-ndk构建Rust部分
iOS
iOS构建步骤:
- 编写使用btleplug并暴露C API的Rust静态库
- 使用cbindgen生成C头文件
- 使用cargo-lipo构建通用静态库
- 将头文件和库拖入Xcode项目
- 在Info.plist中添加NSBluetoothAlwaysUsageDescription
替代库
如果btleplug不符合需求,可以考虑:
- Bluest - 跨平台BLE库(Windows/macOS/iOS/Linux)
- Bluey - 跨平台BLE库(Windows/Android)
- Bluer - Linux上的Bluez官方Rust接口
许可证
btleplug采用BSD 3-Clause许可证,部分代码来自Rumble/Blurmac,采用MIT/Apache双许可证和BSD 3-Clause许可证。
1 回复
Rust蓝牙低功耗(BLE)开发库btleplug使用指南
完整示例代码
下面是一个完整的btleplug使用示例,整合了设备扫描、连接、读写特征值和订阅通知等功能:
use btleplug::api::{Central, CentralEvent, Manager as _, Peripheral, ScanFilter, WriteType};
use btleplug::platform::{Adapter, Manager, Peripheral as BtlePeripheral};
use futures::stream::StreamExt;
use tokio::time::{sleep, Duration};
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// 1. 初始化适配器
let manager = Manager::new().await?;
let adapter = manager.adapters().await?.into_iter().nth(0).ok_or("没有可用的蓝牙适配器")?;
println!("使用适配器: {}", adapter.adapter_info().await?);
// 2. 扫描设备
scan_devices(&adapter).await?;
// 3. 连接设备
let device = connect_to_device(&adapter).await?;
// 4. 发现服务
device.discover_services().await?;
// 5. 读取特征值
if let Some(char) = find_readable_characteristic(&device) {
let value = device.read(&char).await?;
println!("读取到特征值: {:?}", value);
}
// 6. 写入特征值
if let Some(char) = find_writable_characteristic(&device) {
let data = vec![0x01, 0x02];
device.write(&char, &data, WriteType::WithoutResponse).await?;
println!("写入特征值成功");
}
// 7. 订阅通知
if let Some(char) = find_notifiable_characteristic(&device) {
subscribe_notifications(&device, &char).await?;
sleep(Duration::from_secs(5)).await;
}
// 8. 断开连接
device.disconnect().await?;
Ok(())
}
async fn scan_devices(adapter: &Adapter) -> Result<(), Box<dyn Error>> {
println!("开始扫描BLE设备...");
adapter.start_scan(ScanFilter::default()).await?;
sleep(Duration::from_secs(5)).await;
adapter.stop_scan().await?;
let devices = adapter.peripherals().await?;
for device in devices {
let props = device.properties().await?;
println!("发现设备: {:?}, RSSI: {:?}", props.local_name, props.rssi);
}
Ok(())
}
async fn connect_to_device(adapter: &Adapter) -> Result<BtlePeripheral, Box<dyn Error>> {
let devices = adapter.peripherals().await?;
let device = devices.first().ok_or("没有发现设备")?;
if !device.is_connected().await? {
device.connect().await?;
println!("已连接到设备");
}
Ok(device.clone())
}
fn find_readable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
device.services()
.iter()
.flat_map(|service| &service.characteristics)
.find(|c| c.properties.read)
.cloned()
}
fn find_writable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
device.services()
.iter()
.flat_map(|service| &service.characteristics)
.find(|c| c.properties.write)
.cloned()
}
fn find_notifiable_characteristic(device: &BtlePeripheral) -> Option<btleplug::api::Characteristic> {
device.services()
.iter()
.flat_map(|service| &service.characteristics)
.find(|c| c.properties.notify)
.cloned()
}
async fn subscribe_notifications(device: &BtlePeripheral, characteristic: &btleplug::api::Characteristic) -> Result<(), Box<dyn Error>> {
device.subscribe(characteristic).await?;
let mut notification_stream = device.notifications().await?;
tokio::spawn(async move {
while let Some(data) = notification_stream.next().await {
println!("收到通知: {:?}", data.value);
}
});
Ok(())
}
代码说明
- 初始化适配器:通过
Manager
获取系统蓝牙适配器 - 扫描设备:扫描5秒并打印发现的BLE设备信息
- 连接设备:连接到第一个发现的设备
- 发现服务:发现设备提供的所有服务
- 读取特征值:查找并读取第一个可读特征的值
- 写入特征值:查找并写入第一个可写特征
- 订阅通知:查找并订阅第一个支持通知的特征
- 断开连接:最后断开设备连接
使用说明
- 将上述代码保存为
main.rs
- 确保
Cargo.toml
中包含正确的依赖:
[dependencies]
btleplug = "0.10"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"
-
根据平台安装必要依赖:
- Linux:
sudo apt-get install libbluetooth-dev bluez
- 其他平台请参考前面的平台注意事项
- Linux:
-
运行程序:
cargo run
这个完整示例演示了btleplug库的主要功能,包括设备发现、连接管理、数据读写和通知处理,可以作为开发BLE应用的起点。