iOS 藍(lán)牙

1.藍(lán)牙的基礎(chǔ)知識

1. iOS中開發(fā)藍(lán)牙常用的系統(tǒng)庫是<CoreBluetooth/CoreBluetooth.h>。

2.藍(lán)牙外設(shè)必需為4.0及以上(2.0需要MFI認(rèn)證),否則無法進(jìn)行開發(fā),藍(lán)牙4.0設(shè)施由于低耗電,所以也叫做BLE。

3. CoreBluetooth框架的核心其實(shí)是倆東西

? ? 3.1 Peripheral

? ? 3.2?Central

4. 服務(wù)和特征(service characteristic):簡而言之,外部藍(lán)牙中它有若干個(gè)服務(wù)service(服務(wù)你能了解為藍(lán)牙所擁有的可以力),而每個(gè)服務(wù)service下?lián)碛腥舾蓚€(gè)特征characteristic(特征你能了解為解釋這個(gè)服務(wù)的屬性)。

5. Descriptor(形容)使用來形容characteristic變量的屬性。例如,一個(gè)descriptor能規(guī)定一個(gè)可讀的形容,或者者一個(gè)characteristic變量可接受的范圍,或者者一個(gè)characteristic變量特定的單位。

2.藍(lán)牙流程圖

3. 藍(lán)牙連接的主要步驟

? ? ?3.1 創(chuàng)建一個(gè)CBCentralManager實(shí)例來進(jìn)行藍(lán)牙管理;

? ? ?3.2 搜索掃描外圍設(shè)備;

?????3.3 連接外圍設(shè)備;

? ? ?3.4 獲得外圍設(shè)備的服務(wù);

? ? ?3.5 獲得服務(wù)的特征;

? ? ?3.6 從外圍設(shè)備讀取數(shù)據(jù);

? ? ?3.7 給外圍設(shè)備發(fā)送(寫入)數(shù)據(jù)。

4.如何掃描藍(lán)牙

?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對應(yīng)的是一個(gè)唯一標(biāo)識的字符串,用于藍(lán)牙進(jìn)程被殺掉恢復(fù)連接時(shí)使用

4.2 掃描

/*

?*掃描設(shè)備

?*/

- (void)scanForDevices:(NSError**)error

{

? ? if (CBCentralManagerStatePoweredOn == self.centralManager.state) {

? ? ? ? //取回已連接的service設(shè)備

? ? ? ? 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 發(fā)現(xiàn)外圍設(shè)備

- (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 連接外圍設(shè)備

//藍(lán)牙連接成功回調(diào)

- (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);

? ? //定時(shí)獲取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?連接外設(shè)——失敗

-?(void)centralManager:(CBCentralManager?*)central?didFailToConnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error{

????NSLog(@"%@",?error);

}

#pragma?mark?取消與外設(shè)的連接回調(diào)

-?(void)centralManager:(CBCentralManager?*)central?didDisconnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error{

????NSLog(@"%@",?peripheral);

}

4.5?獲得外圍設(shè)備的服務(wù)

//發(fā)現(xiàn)服務(wù)的回調(diào)

- (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];

? ? }

}

//發(fā)現(xiàn)特征的回調(diào)

- (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訂閱特性當(dāng)數(shù)據(jù)頻繁改變時(shí)用 setNotifyValue 不頻繁時(shí)用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 授權(quán)認(rèn)證

? ? ? ? [self.delegate clientDidPrepareForOperation:self];

? ? }

//? ? [self.delegate clientDidPrepareForOperation:self];

}

4.6?從外圍設(shè)備讀取數(shù)據(jù)

// peripheral主動發(fā)數(shù)據(jù),包括寫命令后主動返回的狀態(tài) 讀數(shù)據(jù)的回調(diào)

- (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?給外圍設(shè)備發(fā)送(寫入)數(shù)據(jù)

- (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];//對于操控類藍(lán)牙,數(shù)據(jù)寫入要求非常快,其中writeWithSponce寫入消耗的時(shí)間是writeWithoutSponce的2.3倍,因此盡量改寫成writeWithoutSponce來提升寫入速率

? ? ? ??returnisLastSegment;

?}

//是否寫入成功的回調(diào)

- (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 如何解析藍(lán)牙數(shù)據(jù)


//判斷是否第一個(gè)包,若是,取出包長度

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容