蓝牙开发,现在普遍的都是BLE4.0低功耗蓝牙,CoreBluetooth是iOS 开发I比较推荐的一种开发方法
CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。(例如:你的小米手环就是peripheral,而你的手机就是central,)
iOS 开发APP一般都只会用到central,所以这里主要讲APP 怎么与你的蓝牙外设交互.
蓝牙开发步骤:
建立中心角色—扫描外设(discover)—连接外设(connect)—扫描外设中的服务和特征(discover)—与外设做数据交互(explore and interact)—断开连接(disconnect)。
直接上代码:首先导入头文件#import
建立中心角色:
CBCentralManager *m_manger; = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
扫描外设:
NSArray *array_service = [NSArray arrayWithObjects:[CBUUID UUIDWithString:@"FFE7"],nil];
//扫描设备第一参数如果是nil 表示搜索所有的设备,
[m_manger scanForPeripheralsWithServices:array_service options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES,CBCentralManagerScanOptionSolicitedServiceUUIDsKey : services }];
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
//这个方法是一旦扫描到外设就会调用的方法,注意此时并没有连接上外设,这个方法里面,你可以解析出当前扫描到的外设的广播包信息,当前RSSI等,现在很多的做法是,会根据广播包带出来的设备名,初步判断是不是自己公司的设备,才去连接这个设备,就是在这里面进行判断的
[m_manger connectPeripheral:peripheral options:nil];//连接设备,你可以存到数组中,确定你连接哪一个
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;{ [m_manger stopScan];
m_peripheral = peripheral;
m_peripheral.delegate = self;
NSLog(@"已经连接上了: %@",peripheral);
//我们直接一次读取外设的所有的: Services ,如果只想找某个服务,直接传数组进去就行,比如你只想扫描服务UUID为 FFF1和FFE2 的这两项服务 // NSArray *array_service = [NSArray arrayWithObjects:[CBUUID UUIDWithString:@"FFE7"],nil]; // [m_peripheral discoverServices:array_service];
[m_peripheral discoverServices:nil];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;{
//自己看看官方的说明,这个函数被调用是有前提条件的,首先你的要先调用过了 connectPeripheral:options:这个方法,其次是如果这个函数被回调的原因不是因为你主动调用了 cancelPeripheralConnection 这个方法,那么说明,整个蓝牙连接已经结束了,不会再有回连的可能,得要重来了 NSLog(@"didDisconnectPeripheral"); //如果你想要尝试回连外设,可以在这里调用一下链接函数
[central connectPeripheral:peripheral options:@{CBCentralManagerScanOptionSolicitedServiceUUIDsKey : @YES,CBConnectPeripheralOptionNotifyOnDisconnectionKey:@YES}];
}
- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0);{
//这个函数一般不会被调用,他被调用是因为 peripheral.name 被修改了,才会被调用
}
- (void)peripheralDidInvalidateServices:(CBPeripheral *)peripheral NS_DEPRECATED(NA, NA, 6_0, 7_0);{
//这个函数一般也不会被调用,它是在你已经读取过一次外设的 services 之后,没有断开,这个时候外设突然来个我的某个服务不让用了,这个时候才会被调用,你得要再一次读取外设的 services 即可
}
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error NS_DEPRECATED(NA, NA, 5_0, 8_0);{
//这个函数一看就知道了,当外设更新了RSSI的时候被调用,当然,外设不会无故给你老是发RSSI,听硬件那边工程师说,蓝牙协议栈里面的心跳包是可以把RSSI带过来的,但是不知道什么情况,被封杀了,你的要主动调用 [peripheral readRSSI];方法,人家外设才给你回RSSI,不过这个方法现在被弃用了。用下面的方法来接收 //已经弃用
}
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error NS_AVAILABLE(NA, 8_0);{
//同上,这个就是你主动调用了 [peripheral readRSSI];方法回调的RSSI,你可以根据这个RSSI估算一下距离什么的 NSLog(@" peripheral Current RSSI:%@",RSSI);
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;{
//到这里,说明你上面调用的 [m_peripheral discoverServices:nil]; 方法起效果了,我们接着来找找特征值UUID NSLog(@"%@",peripheral.services);
NSArray *services = nil;
if (peripheral != self.m_peripheral) {
NSLog(@"Wrong Peripheral.\n"); return ;
}
if (error != nil) {
NSLog(@"Error %@", error); return ;
}
services = [peripheral services];
if (!services || ![services count]) {
NSLog(@"No Services");
return ;
}
//遍历所有的服务 读取所有的特征
for (CBService *service in services) {
NSLog(@"service是:%@",service.UUID);
[peripheral discoverCharacteristics:nil forService:service];
}
}/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error;{
NSLog(@"service%@",service); //基本用不上
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;{
//发现了(指定)的特征值了,如果你想要有所动作,你可以直接在这里做,比如有些属性为 notify 的 Characteristics ,你想要监听他们的值,可以这样写 NSLog(@"发现了特征值");
for (CBCharacteristic *c in service.characteristics) {
if ([[c.UUID UUIDString]isEqualToString:@"FEC7"]) {
_writeCharacteristic = c;
}
NSLog(@"_writeCharacteristic %@",c.UUID);
if ([[c.UUID UUIDString] isEqualToString:@"FEC7"]) {
[peripheral setNotifyValue:YES forCharacteristic:c]; //不想监听的时候,设置为:NO 就行了
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;{
//这个可是重点了,你收的一切数据,基本都从这里得到,你只要判断一下 [characteristic.UUID UUIDString] 符合你们定义的哪个,然后进行处理就行,值为:characteristic.value 一切数据都是这个,至于怎么解析,得看你们自己的了 //[characteristic.UUID UUIDString] 注意: UUIDString 这个方法是IOS 7.1之后才支持的,要是之前的版本,得要自己写一个转换方法
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;{
//这个方法比较好,这个是你发数据到外设的某一个特征值上面,并且响应的类型是 CBCharacteristicWriteWithResponse ,上面的官方文档也有,如果确定发送到外设了,就会给你一个回应,当然,这个也是要看外设那边的特征值UUID的属性是怎么设置的,看官方文档,人家已经说了,条件是,特征值UUID的属性:CBCharacteristicWriteWithResponse
//NSLog(@"%@",error);
if (!error) {
NSLog(@"发送成功,characteristic.uuid为:%@",[characteristic.UUID UUIDString]);
}else{
NSLog(@"发送失败了啊!characteristic.uuid为:%@ %@",[characteristic.UUID UUIDString],error);
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;{
//这个方法被调用是因为你主动调用方法: setNotifyValue:forCharacteristic 给你的反馈
NSLog(@"你更新了对特征值:%@ 的通知",[characteristic.UUID UUIDString]);
}