iOS开发 蓝牙功能

本文详细介绍了在iOS开发中如何使用CBCentralManager和CBPeripheral进行蓝牙功能的中心设备扫描、连接外设以及服务、特征和描述符的操作流程,包括状态管理、服务发现和数据传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iOS开发蓝牙功能主要分扫描中心和外设设备

Central中心设备,发起蓝牙连接的设备(一般指手机)
Peripheral: 外设,被蓝牙连接的设备(一般是运动手环/蓝牙模块)
Service:服务,每个设备会提供服务,一个设备有很多服务
Characteristic:特征,每个服务中包含很多个特征,这些特征的权限一般分为:读(read)/写(write)/通知(notice)几种,可以通过特征进行读写数据(重要角色)(中心设备写入数据的时候一定要找到可写入特征才可以写入成功)
Descriptor:描述者,每个特征可以对应一个或者多个描述者,用于描述特征的信息或者属性

准备工作,iOS设备,接入#import <CoreBluetooth/CoreBluetooth.h>,一台手机作为中心设备,一台手机作为外设(或者蓝牙设备硬件),外安装一个蓝牙调试助手作为辅助工具,查找那些特征是可写,可读等等。

以下是流程代码

1.中心设备开启扫描,调用即可[self mCentral];

- (CBCentralManager *)mCentral
{
    if (!_mCentral) {
        _mCentral = [[CBCentralManager alloc] initWithDelegate:self
                                                         queue:dispatch_get_main_queue()
                                                       options:nil];
    }
    return _mCentral;
}

2.中心设备初始化后,调用以下代理方法(必须实现的)

//2、只要中心管理者初始化,就会触发此代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{

    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@"CBCentralManagerStateUnknown");
            break;
        case CBManagerStateResetting:
            NSLog(@"CBCentralManagerStateResetting");
            break;
        case CBManagerStateUnsupported:
            NSLog(@"CBCentralManagerStateUnsupported");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"CBCentralManagerStateUnauthorized");
            break;
        case CBManagerStatePoweredOff:
            NSLog(@"CBCentralManagerStatePoweredOff");
            break;
        case CBManagerStatePoweredOn:
        {
            NSLog(@"CBCentralManagerStatePoweredOn");
            //3、搜索外设
            [self.mCentral scanForPeripheralsWithServices:nil // 通过某些服务筛选外设
                                              options:nil]; // dict,条件
        }
            break;
        default:
            break;
    }
}

3.发现外部设备后(蓝牙设备)的回调方法

//4、发现外设后调用的方法
- (void)centralManager:(CBCentralManager *)central // 中心管理者
 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设
     advertisementData:(NSDictionary *)advertisementData // 外设携带的数据
                  RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度
{
    if (peripheral.name) {
        [self.dataArr addObject:peripheral];
    }
    
    [self.tableView reloadData];
    //(ABS(RSSI.integerValue) > 35)
    //5、发现完之后就是进行连接
    if([peripheral.name isEqualToString:mBLEName]){
        self.mPeripheral = peripheral;
        self.mPeripheral.delegate = self;
        [self.mCentral connectPeripheral:peripheral options:nil];
    }
}

4.确定要连接哪个蓝牙设备(我这里用的是tableView显示发现的外部蓝牙设备,所以在这个代理方法里面点击具体某个设备即可)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    CBPeripheral *per = self.dataArr[indexPath.row];
    self.mPeripheral = per;
    self.mPeripheral.delegate = self;
    [self.mCentral connectPeripheral:per options:nil];
}

5.中心设备链接外部设备成功,失败,丢失的回调方法,如果需要自动重连,可以失败,丢失接口里面重新调用连接


//6、中心管理者连接外设成功
- (void)centralManager:(CBCentralManager *)central // 中心管理者
  didConnectPeripheral:(CBPeripheral *)peripheral // 外设
{
    NSLog(@"%@==设备连接成功", peripheral.name);
    //7、外设发现服务,传nil代表不过滤
    [self.mPeripheral discoverServices:nil];
}

// 外设连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"设备连接失败==%@", peripheral.name);
}

// 丢失连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"设备丢失连接==%@", peripheral.name);
}

6.连接蓝牙成功以后实现以下回调,查找我们需要的特征,跟进具体某个特征是否可写,可读,进行记录,后续作为写入和读取数据使用(查询是否可写可读时可以手机安装一个蓝牙调试助手查看)

//8、发现外设的服务后调用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    // 是否获取失败
    if (error) {
        NSLog(@"备获取服务失败==%@", peripheral.name);
        return;
    }
    for (CBService *service in peripheral.services) {
        self.mService = service;
        NSLog(@"发现外设的服务后调用的方法 设备的服务==%@,UUID==%@,count==%lu",service,service.UUID,peripheral.services.count);
        //9、外设发现特征
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

//10、发现外设特征的时候调用的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    //这里面校验哪些特征值是可写或者可读 ,这里可以使用手机端搜索蓝牙调试助手,查看哪些特征服务可写
    for (CBCharacteristic *cha in service.characteristics) {
        if([cha.UUID.UUIDString isEqualToString:@"8667556C-9A37-4C91-84ED-54EE27D90049"]){//找到可写的特征
            self.mCharacteristic = cha;
            NSLog(@"从服务中发现外设特征的时候调用的代理方法设备的服务==%@,服务对应的特征值==%@,UUID==%@---%@,",service,cha,cha.UUID,cha.UUID.UUIDString);
            //11、获取特征对应的描述 会回调didUpdateValueForDescriptor
            [peripheral discoverDescriptorsForCharacteristic:cha];
            //12、获取特征的值 会回调didUpdateValueForCharacteristic
            [peripheral readValueForCharacteristic:cha];
            //打开外设的通知,否则无法接受数据
            [peripheral setNotifyValue:YES forCharacteristic:self.mCharacteristic];
        }
    }

}

//13、更新描述值的时候会调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
    NSLog(@"描述==%@",descriptor.description);
}

//14、更新特征值的时候调用,可以理解为获取蓝牙发回的数据 获取外设发来的数据,不论是read和notify,获取数据都从这个方法中读取
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    NSData* data = characteristic.value;
    NSString* value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"uuid:%@ value : %@",characteristic.UUID,value);
}

//15、通知状态改变时调用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if(error){
        NSLog(@"改变通知状态");
    }
}

//16、发现外设的特征的描述数组
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
    // 在此处读取描述即可
    for (CBDescriptor *descriptor in characteristic.descriptors) {
        self.mDescriptor = descriptor;
        NSLog(@"发现外设的特征descriptor==%@",descriptor);
    }
}

7。写入数据以及写入失败成功回调(写入数据时候的特征一定要是可写的特征,这个上一步那里可以知道)

//17、发送数据
- (void)send{

    // 核心代码在这里
    
    [self.mPeripheral writeValue:[@"写数据" dataUsingEncoding:NSUTF8StringEncoding]// 写入的数据
         forCharacteristic:self.mCharacteristic // 写给哪个特征(这个特征必须是可写特征才能写入成功,因为一个蓝牙外设可以有很多个服务,很多特征)
                      type:CBCharacteristicWriteWithResponse];// 通过此响应记录是否成功写入
}

//向peripheral中写入数据后的回调函数
- (void)peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"写入失败%@",error);
        return;
    }
    NSLog(@"write value success(写入成功) : %@===%@", characteristic,[[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]);
}

到此,中心设备相关实现就完成了,如果是跟蓝牙硬件交互,只需要跟硬件相关人员协调写入数据和读取数据的各种格式,以及写入哪个特征等等即可

以下是外部设备相关实现,也就是如果把手机作为外设时候的代码实现

1.定义外设,初始化外设相关名称,代码

@interface NoticePeripheraManagerViewController ()<CBPeripheralManagerDelegate>
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) UILabel *statusL;
@property (strong, nonatomic) NSData                    *dataToSend;
@property (nonatomic, strong) CBMutableCharacteristic *cumCharacteristic;
@end

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];
    self.statusL = [[UILabel alloc] initWithFrame:self.view.bounds];
    self.statusL.textColor = [UIColor blackColor];
    self.statusL.font = [UIFont systemFontOfSize:18];
    self.statusL.numberOfLines = 0;
    [self.view addSubview:self.statusL];
    /*
      和CBCentralManager类似,蓝牙设备打开需要一定时间,打开成功后会进入委托方法
      - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
      模拟器永远也不会得CBPeripheralManagerStatePoweredOn状态
      */
     self.peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
     // 初始化数据
     self.dataToSend = [@"snadjfkhaw加大困难的是咖啡euijferlfmn ksxncjxznvjeajfrnjadnfjasfndsafnjsadkfnjsa" dataUsingEncoding:NSUTF8StringEncoding];
}
//peripheralManager状态改变
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    switch (peripheral.state) {
            //在这里判断蓝牙设别的状态  当开启了则可调用  setUp方法(自定义)
        case CBManagerStatePoweredOn:
            NSLog(@"powered on");
          
            self.statusL.text = [NSString stringWithFormat:@"设备名%@已经打开,可以使用center进行连接",@"ios设备"];
            [self setUp];
            break;
        case CBManagerStatePoweredOff:
            NSLog(@"powered off");
  
            self.statusL.text = @"powered off";
            break;

        default:
            break;
    }
}

- (void)setUp{
    
    /*
     typedef NS_OPTIONS(NSUInteger, CBAttributePermissions) {
         CBAttributePermissionsReadable                  = 0x01,         //可读
         CBAttributePermissionsWriteable                 = 0x02,         //可写
         CBAttributePermissionsReadEncryptionRequired    = 0x04,                 //可读,需要建立安全连接
         CBAttributePermissionsWriteEncryptionRequired   = 0x08             // //可写,需要建立安全连接
     } NS_ENUM_AVAILABLE(10_9, 6_0);
     */
    
    CBMutableCharacteristic *writeReadCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"FF01"] properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite  value:nil permissions:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite];
    CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"FF66"] primary:YES];
    [service setCharacteristics:@[writeReadCharacteristic]];
    self.cumCharacteristic = writeReadCharacteristic;
    [self.peripheralManager addService:service];
    

}

//添加了服务回调
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    NSLog(@"添加服务成功开始广播");
    [self.peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:@"FF66"]],CBAdvertisementDataLocalNameKey:@"ios设备"}];
}


//当中央端连接上了此设备并订阅了特征时会回调 didSubscribeToCharacteristic:
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
    NSLog(@"当中央端连接上了此设备并订阅了特征时会回调");
    [self.peripheralManager updateValue:[@"订阅特征" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic onSubscribedCentrals:nil];
}



//当接收到中央端读的请求时会调用didReceiveReadRequest:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {
    if (request.characteristic.properties & CBCharacteristicPropertyRead) {
        NSData *data = [@"收到读的请求" dataUsingEncoding:NSUTF8StringEncoding];
        self.statusL.text = @"收到读的请求";
        [request setValue:data];
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    } else {
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorReadNotPermitted];
    }
}

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
    self.statusL.text = @"收到写的请求";
  NSData *res= [[NSString stringWithFormat:@"Hello"] dataUsingEncoding:NSUTF8StringEncoding];
 [self.peripheralManager updateValue:res
                        forCharacteristic:self.cumCharacteristic
                     onSubscribedCentrals:nil];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值