1.蓝牙的基础知识
1. iOS中开发蓝牙常用的系统库是
2.蓝牙外设必需为4.0及以上(2.0需要MFI认证),否则无法进行开发,蓝牙4.0设施由于低耗电,所以也叫做BLE。
3. CoreBluetooth框架的核心其实是俩东西
3.1 Peripheral
3.2 Central
4. 服务和特征(service characteristic):简而言之,外部蓝牙中它有若干个服务service(服务你能了解为蓝牙所拥有的可以力),而每个服务service下拥有若干个特征characteristic(特征你能了解为解释这个服务的属性)。
5. Descriptor(形容)使用来形容characteristic变量的属性。例如,一个descriptor能规定一个可读的形容,或者者一个characteristic变量可接受的范围,或者者一个characteristic变量特定的单位。
2.蓝牙流程图
3. 蓝牙连接的主要步骤
3.1 创建一个CBCentralManager实例来进行蓝牙管理;
3.2 搜索扫描外围设备;
3.3 连接外围设备;
3.4 获得外围设备的服务;
3.5 获得服务的特征;
3.6 从外围设备读取数据;
3.7 给外围设备发送(写入)数据。
4.如何扫描蓝牙
4.1 初始化
dispatch_queue_t centralQueue = dispatch_queue_create(“centralQueue",DISPATCH_QUEUE_SERIAL);
NSDictionary *dic = @{CBCentralManagerOptionRestoreIdentifierKey : restoreIdentifier};
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:dic];
CBCentralManagerOptionRestoreIdentifierKey对应的是一个唯一标识的字符串,用于蓝牙进程被杀掉恢复连接时使用
4.2 扫描
/*
*扫描设备
*/
- (void)scanForDevices:(NSError**)error
{
if (CBCentralManagerStatePoweredOn == self.centralManager.state) {
//取回已连接的service设备
NSArray* retrievedPeripherals = [self.centralManagerretrieveConnectedPeripheralsWithServices:@[self.serviceUUID]];
for(CBPeripheral* peripheralinretrievedPeripherals){
//NSLog(@"retrieved peripheral:%@", peripheral);
[self.delegateclient:selfdidDiscoverDevice:peripheral.identifier];
}
//启动扫描
if (self.advertisementUUID) {
[self.centralManager scanForPeripheralsWithServices:@[ self.advertisementUUID ] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey:@YES }];
}else{
[self.centralManager scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey:@YES }];
// [self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
}else{
if(error !=NULL) {
*error = [NSErrorerrorWithDomain:HCErrorDomaincode:(SRVClientErrorUnknown+self.centralManager.state)userInfo:nil];
NSLog(@"[NSError errorWithDomain:HCErrorDomain code:(SRVClientErrorUnknown + self.centralManager.state) userInfo:nil];");
}
}
}
4.3 发现外围设备
- (void)centralManager:(CBCentralManager*)centraldidDiscoverPeripheral:(CBPeripheral*)peripheraladvertisementData:(NSDictionary*)advertisementDataRSSI:(NSNumber*)RSSI {
NSString*peripheralName = peripheral.name;
if(peripheralName ==nil|| peripheralName.length==0) {
return;
}
if([peripheralNameisEqualToString:SRV_CLIENT_DEV_NAME] || [peripheralNameisEqualToString:SRV_CLIENT_DFU_NAME]) {
}
}
4.4 连接外围设备
//蓝牙连接成功回调
- (void)centralManager:(CBCentralManager*)centraldidConnectPeripheral:(CBPeripheral*)peripheral {
[self.centralManager stopScan];
peripheral.delegate=self;
self.commandNo=0;
NSLog(@"[D] CentralManager Discover services.");
NSLog(@"%@",self.peripheral);
self.peripheral.delegate=self;
[self.peripheral discoverServices:@[self.serviceUUID]];
NSLog(@"%@",self.serviceUUID);
//定时获取RSSI
if (self.needReadRSSI) {
[self readPeripheralRSSI];
if(!self.rssiTimer) {
self.rssiTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(readPeripheralRSSI)
userInfo:nil
repeats:YES];
}
}
}
#pragma mark 连接外设——失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%@", error);
}
#pragma mark 取消与外设的连接回调
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%@", peripheral);
}
4.5 获得外围设备的服务
//发现服务的回调
- (void)peripheral:(CBPeripheral*)peripheraldidDiscoverServices:(NSError*)error
{
NSLog(@"%@---didDiscoverServices",peripheral);
if(error){
NSLog(@"[E] peripheral didDiscoverServices error: %@", error.localizedDescription);
[self cancelConnection];
return;
}
for(CBService* serviceinperipheral.services){
NSLog(@"[D] Discover characteristics. For service = %@", service);
[peripheraldiscoverCharacteristics:nil forService:service];
}
}
//发现特征的回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if(error){
NSLog(@"[E] peripheral didDiscoverCharacteristicsForService error: %@", error.localizedDescription);
[self cancelConnection];
return;
}
NSLog(@"[D] peripheral DiscoverCharacteristics = %@", service.characteristics);
//订阅特征
for(CBCharacteristic*characteristicinservice.characteristics){
if (characteristic.properties & (CBCharacteristicPropertyNotify|CBCharacteristicPropertyIndicate)){
if(!characteristic.isNotifying) {
if([self.ignoreCharacteristicUUIDscontainsObject:characteristic.UUID]) {
continue;
}
NSLog(@"[D] Enable notify value. For characteristic = %@", characteristic);
//d订阅特性当数据频繁改变时用 setNotifyValue 不频繁时用readValueForCharacteristic
[peripheralsetNotifyValue:YESforCharacteristic:characteristic];
}
}
}
}
// 订阅后的callback
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if(error){
NSLog(@"[E] peripheral didUpdateNotificationStateForCharacteristic error: %@", error.localizedDescription);
[self cancelConnection];
return;
}
if ([self isAllCharacteristicNotificationEnabled]){
NSLog(@"订阅成功");
//authorizeRequest 授权认证
[self.delegate clientDidPrepareForOperation:self];
}
// [self.delegate clientDidPrepareForOperation:self];
}
4.6 从外围设备读取数据
// peripheral主动发数据,包括写命令后主动返回的状态 读数据的回调
- (void)peripheral:(CBPeripheral*)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error
{
if(error) {
NSLog(@"[E] peripheral didUpdateValueForCharacteristic error: %@ %@", error.localizedDescription,characteristic);
[self cancelConnection];
[self cleanupOperationUnexpectedly];
return;
}
NSLog(@"%@",peripheral);
NSLog(@"%@",characteristic);
[self.delegate client:self didUpdateValueForCharacteristic:characteristic.UUID value:characteristic.value];
if([characteristic.UUIDisEqual:self.ctrlptUUID]) {
if (CTRLPTProgressWaitResp == self.ctrlptProgress) {
}
}
}
4.7 给外围设备发送(写入)数据
- (BOOL)performOperationSegment:(CBCharacteristic*)characteristic
{
BOOLisLastSegment;
uint8_tsegment[20];
uint16_tindex =0;
uint16_tsegLength;
NSIntegerforwardLength =self.forwardFlow.length;
if((forwardLength -self.forwardOffset) > (20- index)) {
isLastSegment =NO;
segLength = (20- index);
}else{
isLastSegment =YES;
segLength = (forwardLength -self.forwardOffset);
}
memcpy(&segment[index], &self.forwardFlow.bytes[self.forwardOffset], segLength);
self.forwardOffset+= segLength;
index += segLength;
NSData*writeData = [NSDatadataWithBytes:segmentlength:index];
NSLog(@"[D] Write value = %@. For characteristic = %@", writeData, characteristic);
[self.peripheral writeValue:writeData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];//对于操控类蓝牙,数据写入要求非常快,其中writeWithSponce写入消耗的时间是writeWithoutSponce的2.3倍,因此尽量改写成writeWithoutSponce来提升写入速率
returnisLastSegment;
}
//是否写入成功的回调
- (void)peripheral:(CBPeripheral*)peripheraldidWriteValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error
{
if(error) {
NSLog(@"[E] peripheral didWriteValueForCharacteristic error: %@", error);
[self cancelConnection];
[self cleanupOperationUnexpectedly];
return;
}
NSLog(@"写入成功----%@",characteristic);
if([characteristic.UUIDisEqual:self.ctrlptUUID]) {
if (CTRLPTProgressWritting == self.ctrlptProgress) {
if([selfperformOperationSegment:characteristic]) {
self.ctrlptProgress = CTRLPTProgressWaitResp;
self.backwardFlow.length=0;
self.backwardOffset=0;
}
}
}
}
4.8 如何解析蓝牙数据
//判断是否第一个包,若是,取出包长度
if(0==self.backwardOffset&& length >=2) {
uint16_tcommandLength;
[characteristicDatagetBytes:&commandLengthlength:sizeof(commandLength)];
offset +=sizeof(commandLength);
self.backwardLength= commandLength;
[self.backwardFlowappendData:[characteristicDatasubdataWithRange:NSMakeRange(offset, length - offset)]];
}else{
[self.backwardFlowappendData:characteristicData];
}