Rust蓝牙开发库objc2-core-bluetooth的使用:跨平台蓝牙设备连接与通信的核心功能实现
Rust蓝牙开发库objc2-core-bluetooth的使用:跨平台蓝牙设备连接与通信的核心功能实现
objc2-core-bluetooth
是Rust对苹果CoreBluetooth框架的绑定库。
安装
在项目目录中运行以下Cargo命令:
cargo add objc2-core-bluetooth
或者在Cargo.toml中添加以下行:
objc2-core-bluetooth = "0.3.1"
使用示例
下面是一个增强版的完整蓝牙设备通信示例,包含更多细节和错误处理:
use objc2::rc::{Id, Shared};
use objc2::runtime::NSObject;
use objc2_foundation::{NSError, NSString, NSDictionary, NSNumber};
use objc2_core_bluetooth::{
CBManager, CBPeripheral, CBPeripheralDelegate, CBService, CBCharacteristic,
CBCentralManager, CBCentralManagerDelegate, CBUUID, CBManagerState,
CBCharacteristicProperties, CBATTError
};
// 中央管理器状态跟踪
struct BluetoothState {
is_scanning: bool,
connected_devices: Vec<Id<CBPeripheral, Shared>>,
}
// 中央管理器委托实现
#[derive(Debug)]
struct CentralManagerDelegate {
state: BluetoothState,
}
impl CentralManagerDelegate {
fn new() -> Self {
Self {
state: BluetoothState {
is_scanning: false,
connected_devices: Vec::new(),
}
}
}
}
unsafe impl CBCentralManagerDelegate for CentralManagerDelegate {
type CentralManager = Id<CBCentralManager, Shared>;
fn did_update_state(&mut self, central: Self::CentralManager) {
match central.state() {
CBManagerState::PoweredOn => {
println!("蓝牙已开启,开始扫描...");
self.state.is_scanning = true;
central.scan_for_peripherals_with_services(None, None);
},
CBManagerState::PoweredOff => {
println!("蓝牙已关闭");
self.state.is_scanning = false;
},
_ => println!("蓝牙状态改变: {:?}", central.state()),
}
}
fn did_discover_peripheral(
&self,
central: Self::CentralManager,
peripheral: Id<CBPeripheral, Shared>,
advertisement_data: Id<NSDictionary, Shared>,
rssi: Id<NSNumber, Shared>
) {
let name = peripheral.name().unwrap_or_else(|| NSString::from_str("Unknown"));
println!("发现设备: {} (RSSI: {})", name, rssi);
// 检查广告数据
if let Some(services) = advertisement_data.object_for_key(NSString::from_str("kCBAdvDataServiceUUIDs")) {
println!("广告服务UUID: {:?}", services);
}
// 只连接特定设备 - 这里可以添加过滤条件
if name.to_string().contains("MyDevice") {
println!("连接设备: {}", name);
central.connect_peripheral(&peripheral, None);
}
}
fn did_connect_peripheral(
&self,
_central: Self::CentralManager,
peripheral: Id<CBPeripheral, Shared>
) {
println!("成功连接设备: {:?}", peripheral.name());
let delegate = Box::new(PeripheralDelegate::new());
peripheral.set_delegate(Some(delegate));
peripheral.discover_services(None);
}
fn did_fail_to_connect_peripheral(
&self,
_central: Self::CentralManager,
peripheral: Id<CBPeripheral, Shared>,
error: Option<Id<NSError, Shared>>
) {
println!("连接设备失败: {:?}", peripheral.name());
if let Some(err) = error {
println!("错误: {:?}", err);
}
}
fn did_disconnect_peripheral(
&self,
central: Self::CentralManager,
peripheral: Id<CBPeripheral, Shared>,
error: Option<Id<NSError, Shared>>
) {
println!("设备断开连接: {:?}", peripheral.name());
if let Some(err) = error {
println!("错误: {:?}", err);
}
// 自动重连
central.connect_peripheral(&peripheral, None);
}
}
// 外围设备委托实现
#[derive(Debug)]
struct PeripheralDelegate;
impl PeripheralDelegate {
fn new() -> Self {
Self
}
}
unsafe impl CBPeripheralDelegate for PeripheralDelegate {
type Peripheral = Id<CBPeripheral, Shared>;
fn did_discover_services(
&self,
peripheral: Self::Peripheral,
error: Option<Id<NSError, Shared>>
) {
if let Some(err) = error {
println!("发现服务错误: {:?}", err);
return;
}
println!("发现的服务:");
if let Some(services) = peripheral.services() {
for service in services.iter() {
println!("- UUID: {:?}", service.uuid());
// 发现每个服务的特征
peripheral.discover_characteristics(None, &service);
}
}
}
fn did_discover_characteristics_for_service(
&self,
peripheral: Self::Peripheral,
service: Id<CBService, Shared>,
error: Option<Id<NSError, Shared>>
) {
if let Some(err) = error {
println!("发现特征错误: {:?}", err);
return;
}
println!("服务 {} 的特征:", service.uuid());
if let Some(characteristics) = service.characteristics() {
for characteristic in characteristics.iter() {
println!("- UUID: {:?}", characteristic.uuid());
println!(" 属性: {:?}", characteristic.properties());
// 读取可读特征
if characteristic.properties().contains(CBCharacteristicProperties::Read) {
peripheral.read_value_for_characteristic(&characteristic);
}
// 订阅通知
if characteristic.properties().contains(CBCharacteristicProperties::Notify) {
peripheral.set_notify_value(true, &characteristic);
}
}
}
}
fn did_update_value_for_characteristic(
&self,
_peripheral: Self::Peripheral,
characteristic: Id<CBCharacteristic, Shared>,
error: Option<Id<NSError, Shared>>
) {
if let Some(err) = error {
println!("更新特征值错误: {:?}", err);
return;
}
if let Some(value) = characteristic.value() {
println!("特征 {} 更新值: {:?}", characteristic.uuid(), value);
}
}
fn did_write_value_for_characteristic(
&self,
_peripheral: Self::Peripheral,
characteristic: Id<CBCharacteristic, Shared>,
error: Option<Id<NSError, Shared>>
) {
if let Some(err) = error {
println!("写入特征值错误: {:?}", err);
} else {
println!("成功写入特征: {:?}", characteristic.uuid());
}
}
fn did_update_notification_state_for_characteristic(
&self,
_peripheral: Self::Peripheral,
characteristic: Id<CBCharacteristic, Shared>,
error: Option<Id<NSError, Shared>>
) {
if let Some(err) = error {
println!("更新通知状态错误: {:?}", err);
} else {
println!("特征 {} 通知状态更新", characteristic.uuid());
}
}
}
fn main() {
// 创建中央管理器
let delegate = Box::new(CentralManagerDelegate::new());
let _manager = CBCentralManager::new(delegate, None);
println!("蓝牙管理器已创建,等待事件...");
// 运行事件循环
unsafe {
let run_loop = objc2_foundation::CFRunLoopGetCurrent();
objc2_foundation::CFRunLoopRun();
}
}
功能说明
- 蓝牙状态管理:跟踪蓝牙适配器的状态变化
- 设备扫描与过滤:扫描周围设备并可选择性地连接特定设备
- 服务与特征发现:自动发现连接设备的所有服务和特征
- 数据通信:
- 自动读取可读特征值
- 自动订阅支持通知的特征
- 处理特征值更新事件
- 错误处理:全面处理各种蓝牙操作可能产生的错误
- 连接管理:处理设备断开连接并自动重连
许可证
该库采用以下许可证之一:
- Zlib
- Apache-2.0
- MIT
项目信息
- 最新版本:0.3.1
- 分类:API绑定、FFI、外部FFI绑定、macOS API
这个库是objc2
项目的一部分,该项目提供了多个与Objective-C运行时交互的Rust库。
1 回复
Rust蓝牙开发库objc2-core-bluetooth使用指南
介绍
objc2-core-bluetooth
是一个Rust库,它提供了跨平台的蓝牙设备连接与通信功能。这个库封装了不同操作系统(主要是iOS/macOS)的底层蓝牙API,为Rust开发者提供了统一的接口来操作蓝牙设备。
主要功能
- 扫描发现附近的蓝牙设备
- 连接到指定的蓝牙设备
- 发现设备的服务和特征
- 读取和写入特征值
- 订阅特征通知
- 设备连接状态监控
使用方法
添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
objc2-core-bluetooth = "0.1"
objc2 = "0.3"
block = "0.1"
基本使用示例
use objc2::rc::autoreleasepool;
use objc2_core_bluetooth::{CBManager, CBPeripheral, CBUUID};
fn main() {
autoreleasepool(|pool| {
// 创建蓝牙中心管理器
let manager = CBManager::new(pool);
// 开始扫描设备
manager.scan_for_peripherals_with_services(None);
// 设置发现设备回调
manager.set_did_discover_peripheral_callback(Box::new(|peripheral, _| {
println!("发现设备: {:?}", peripheral.name());
// 停止扫描
manager.stop_scan();
// 连接到设备
manager.connect_peripheral(peripheral);
}));
// 设置连接成功回调
manager.set_did_connect_peripheral_callback(Box::new(|peripheral| {
println!("连接成功: {:?}", peripheral.name());
// 发现服务
peripheral.discover_services(None);
}));
// 设置发现服务回调
manager.set_did_discover_services_callback(Box::new(|peripheral, _| {
if let Some(services) = peripheral.services() {
for service in services {
println!("发现服务: {:?}", service.uuid());
// 发现特征
peripheral.discover_characteristics(None, service);
}
}
}));
// 设置发现特征回调
manager.set_did_discover_characteristics_callback(Box::new(|peripheral, service, _| {
if let Some(characteristics) = service.characteristics() {
for characteristic in characteristics {
println!("发现特征: {:?}", characteristic.uuid());
// 订阅特征通知
if characteristic.properties().contains(CBCharacteristicProperties::Notify) {
peripheral.set_notify_value(true, characteristic);
}
}
}
}));
// 设置特征值更新回调
manager.set_did_update_value_for_characteristic_callback(Box::new(|peripheral, characteristic, error| {
if let Some(value) = characteristic.value() {
println!("收到数据: {:?}", value);
}
}));
// 运行事件循环
manager.run_loop();
});
}
高级用法
写入特征值
// 假设已经获取到特征对象 characteristic
let data = vec![0x01, 0x02, 0x03]; // 要写入的数据
peripheral.write_value(data, characteristic, CBCharacteristicWriteType::WithResponse);
读取RSSI值
peripheral.read_rssi();
manager.set_did_read_rssi_callback(Box::new(|peripheral, rssi, _| {
println!("设备 {} 的RSSI: {}", peripheral.name().unwrap_or("未知"), rssi);
}));
完整示例代码
use objc2::rc::autoreleasepool;
use objc2_core_bluetooth::{
CBCharacteristicProperties, CBCharacteristicWriteType, CBManager, CBPeripheral, CBUUID
};
fn main() {
autoreleasepool(|pool| {
// 1. 初始化蓝牙管理器
let manager = CBManager::new(pool);
println!("蓝牙管理器初始化完成,开始扫描设备...");
// 2. 开始扫描蓝牙设备
manager.scan_for_peripherals_with_services(None);
// 3. 设置设备发现回调
manager.set_did_discover_peripheral_callback(Box::new(|peripheral, _| {
println!("发现蓝牙设备: {:?}", peripheral.name());
// 停止扫描
manager.stop_scan();
// 连接到设备
println!("尝试连接设备...");
manager.connect_peripheral(peripheral);
}));
// 4. 设置连接成功回调
manager.set_did_connect_peripheral_callback(Box::new(|peripheral| {
println!("设备连接成功: {:?}", peripheral.name());
// 开始发现服务
println!("开始发现服务...");
peripheral.discover_services(None);
}));
// 5. 设置服务发现回调
manager.set_did_discover_services_callback(Box::new(|peripheral, _| {
if let Some(services) = peripheral.services() {
println!("发现{}个服务", services.len());
for service in services {
println!("服务UUID: {:?}", service.uuid());
// 发现服务特征
peripheral.discover_characteristics(None, service);
}
}
}));
// 6. 设置特征发现回调
manager.set_did_discover_characteristics_callback(Box::new(|peripheral, service, _| {
if let Some(characteristics) = service.characteristics() {
println!("服务 {} 发现{}个特征", service.uuid(), characteristics.len());
for characteristic in characteristics {
println!("特征UUID: {:?}", characteristic.uuid());
println!("特征属性: {:?}", characteristic.properties());
// 如果特征支持通知,则订阅通知
if characteristic.properties().contains(CBCharacteristicProperties::Notify) {
println!("订阅特征通知...");
peripheral.set_notify_value(true, characteristic);
}
// 如果特征可读,则读取特征值
if characteristic.properties().contains(CBCharacteristicProperties::Read) {
println!("读取特征值...");
peripheral.read_value(characteristic);
}
}
}
}));
// 7. 设置特征值更新回调
manager.set_did_update_value_for_characteristic_callback(Box::new(|peripheral, characteristic, error| {
if let Some(value) = characteristic.value() {
println!("特征 {} 收到数据: {:?}", characteristic.uuid(), value);
}
}));
// 8. 设置特征写入完成回调
manager.set_did_write_value_for_characteristic_callback(Box::new(|peripheral, characteristic, error| {
println!("特征 {} 写入完成", characteristic.uuid());
}));
// 9. 运行事件循环
println!("运行事件循环...");
manager.run_loop();
});
}
注意事项
- 在macOS/iOS上使用需要确保应用有蓝牙权限
- 某些操作是异步的,需要通过回调处理结果
- 连接和通信前确保设备已配对(如果需要)
- 使用完毕后应断开连接释放资源
跨平台兼容性
虽然objc2-core-bluetooth
主要面向Apple平台,但可以结合其他Rust蓝牙库(如btleplug
)实现真正的跨平台支持。可以通过条件编译在不同平台使用不同的实现:
#[cfg(target_os = "macos")]
use objc2_core_bluetooth as bluetooth;
#[cfg(not(target_os = "macos"))]
use btleplug as bluetooth;
这个库为Rust开发者提供了在Apple平台上操作蓝牙设备的便捷方式,特别适合需要在macOS或iOS上实现蓝牙功能的Rust应用。