iOS-BLE藍(lán)牙開(kāi)發(fā)

在寫(xiě)這個(gè)博客之前,空余時(shí)間抽看了近一個(gè)月的文檔和Demo谊惭,系統(tǒng)給的解釋很詳細(xì)汽馋,接口也比較實(shí)用,唯獨(dú)有一點(diǎn)圈盔,對(duì)于設(shè)備的唯一標(biāo)示豹芯,網(wǎng)上眾說(shuō)

紛紜,在這里我目前也還沒(méi)有自己的見(jiàn)解驱敲,只是在不斷的測(cè)試各種情況铁蹈,親測(cè)同一設(shè)備的UUID對(duì)于每臺(tái)iPhone設(shè)備都不一樣,只能盡量保證設(shè)備的唯一性众眨,特別是自動(dòng)重連的過(guò)程握牧,讓用戶沒(méi)有感知容诬。我之前也找了很久,發(fā)現(xiàn)CBCentralManager和CBPeripheral里邊都找不到和Mac地址有關(guān)的東西沿腰,后來(lái)發(fā)現(xiàn)一般是外設(shè)在Device Information服務(wù)中的某個(gè)特征返回的览徒。經(jīng)過(guò)與硬件工程師的協(xié)商,決定APP端將從這個(gè)服務(wù)中獲取到藍(lán)牙設(shè)備以及我的iPhone手機(jī)的藍(lán)牙Mac地址矫俺,為自動(dòng)連接的唯一性做準(zhǔn)備。

這里經(jīng)過(guò)和硬件工程師的測(cè)試掸冤,發(fā)現(xiàn)設(shè)備端在獲取手機(jī)藍(lán)牙MAC地址的時(shí)候厘托,當(dāng)用戶手機(jī)重啟之后,這個(gè)地址也是會(huì)隨機(jī)變化的稿湿,也就是說(shuō)铅匹,作為開(kāi)發(fā)者,只有設(shè)備的MAC地址能夠保持唯一性不變化饺藤。

ble.png

有疑問(wèn)的朋友可以先去這里瞅一瞅

一個(gè)關(guān)于藍(lán)牙4.0的智能硬件Demo詳解

下面是兩臺(tái)iPhone6連接同一臺(tái)藍(lán)牙設(shè)備的結(jié)果:

**成功連接**** peripheral:with UUID:<__NSConcreteUUID0x17003d980>50084F69-BA5A-34AC-8A6E-6F0CEADB21CD************成功連接**** peripheral:with UUID:<__NSConcreteUUID0x174036c00>55B7D759-0F1E-6271-EA14-BC5A9C9EEEEC**

進(jìn)入正題

iOS的藍(lán)牙開(kāi)發(fā)很簡(jiǎn)單包斑,只要包含一個(gè)庫(kù),創(chuàng)建CBCentralManager實(shí)例涕俗,實(shí)現(xiàn)代理方法罗丰,然后就可以直接和設(shè)備進(jìn)行通信。

發(fā)現(xiàn)附近的特定藍(lán)牙設(shè)備

#import

首先可以定義一些即將使用到的UUID的宏

#definekPeripheralName? ? @"360qws Electric Bike Service"http://外圍設(shè)備名稱#definekServiceUUID? ? ? ? @"7CACEB8B-DFC4-4A40-A942-AAD653D174DC"http://服務(wù)的UUID#definekCharacteristicUUID @"282A67B2-8DAB-4577-A42F-C4871A3EEC4F"http://特征的UUID

如果不是把手機(jī)作為中心設(shè)備的話再姑,這些沒(méi)有必要設(shè)置萌抵。

這里我也沒(méi)有用到,僅僅是提了一下元镀,具體操作后續(xù)添加绍填。

對(duì)于生成UUID,大家可以谷歌一下栖疑,直接通過(guò)mac終端生成32位UUID讨永。

1.聲明屬性

@property(weak,nonatomic)IBOutletUITableView*bluetoothTable;@property(weak,nonatomic)IBOutletUITextView*resultTextView;@propertyBOOLcbReady;@property(nonatomic)floatbatteryValue;@property(nonatomic,strong) CBCentralManager *manager;@property(nonatomic,strong) CBPeripheral *peripheral;@property(strong,nonatomic) CBCharacteristic *writeCharacteristic;@property(strong,nonatomic)NSMutableArray*nDevices;@property(strong,nonatomic)NSMutableArray*nServices;@property(strong,nonatomic)NSMutableArray*nCharacteristics;

2.遵守協(xié)議(這里我用到了table)

@interfaceViewController ()

3.初始化數(shù)據(jù)

- (void)viewDidLoad {? ? [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.self.manager = [[CBCentralManager alloc] initWithDelegate:selfqueue:nil];? ? _cbReady =false;? ? _nDevices = [[NSMutableArrayalloc]init];? ? _nServices = [[NSMutableArrayalloc]init];? ? _nCharacteristics = [[NSMutableArrayalloc]init];? ? _bluetoothTable.delegate =self;? ? _bluetoothTable.dataSource =self;? ? count =0;}

4.實(shí)現(xiàn)藍(lán)牙的協(xié)議方法

(1)檢測(cè)藍(lán)牙狀態(tài)

//開(kāi)始查看服務(wù),藍(lán)牙開(kāi)啟-(void)centralManagerDidUpdateState:(CBCentralManager *)central{switch(central.state) {caseCBCentralManagerStatePoweredOn:{? ? ? ? ? ? [selfupdateLog:@"藍(lán)牙已打開(kāi),請(qǐng)掃描外設(shè)"];? ? ? ? ? ? [_activity startAnimating];? ? ? ? ? ? [_managerscanForPeripheralsWithServices:@[[CBUUIDUUIDWithString:@"FF15"]]options:@{CBCentralManagerScanOptionAllowDuplicatesKey :@YES}];? ? ? ? }break;caseCBCentralManagerStatePoweredOff:[selfupdateLog:@"藍(lán)牙沒(méi)有打開(kāi),請(qǐng)先打開(kāi)藍(lán)牙"];break;default:break;? ? }}

注:[_manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FF15"]]? options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];中間的@[[CBUUID UUIDWithString:@"FF15"]]是為了過(guò)濾掉其他設(shè)備遇革,可以搜索特定標(biāo)示的設(shè)備卿闹。

(2)檢測(cè)到外設(shè)后,停止掃描萝快,連接設(shè)備

//查到外設(shè)后比原,停止掃描,連接設(shè)備-(void)centralManager:(CBCentralManager *)centraldidDiscoverPeripheral:(CBPeripheral *)peripheraladvertisementData:(NSDictionary *)advertisementDataRSSI:(NSNumber *)RSSI{? ? [selfupdateLog:[NSStringstringWithFormat:@"已發(fā)現(xiàn) peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.identifier, advertisementData]];? ? _peripheral = peripheral;? ? [_managerconnectPeripheral:_peripheraloptions:nil];? ? [self.manager stopScan];? ? [_activity stopAnimating];? ? BOOL replace = NO;// Match if we have this device from beforefor(inti=0; i < _nDevices.count; i++) {? ? ? ? CBPeripheral *p = [_nDevicesobjectAtIndex:i];if([pisEqual:peripheral]) {? ? ? ? ? ? [_nDevicesreplaceObjectAtIndex:iwithObject:peripheral];? ? ? ? ? ? replace = YES;? ? ? ? }? ? }if(!replace) {? ? ? ? [_nDevicesaddObject:peripheral];? ? ? ? [_bluetoothTable reloadData];? ? }}

(3)連接外設(shè)后的處理

//連接外設(shè)成功杠巡,開(kāi)始發(fā)現(xiàn)服務(wù)- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {NSLog(@"%@", [NSStringstringWithFormat:@"成功連接 peripheral: %@ with UUID: %@",peripheral,peripheral.identifier]);? ? [selfupdateLog:[NSStringstringWithFormat:@"成功連接 peripheral: %@ with UUID: %@",peripheral,peripheral.identifier]];? ? [self.peripheral setDelegate:self];? ? [self.peripheral discoverServices:nil];? ? [selfupdateLog:@"掃描服務(wù)"];}//連接外設(shè)失敗-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError*)error{NSLog(@"%@",error);}-(void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError*)error{NSLog(@"%s,%@",__PRETTY_FUNCTION__,peripheral);intrssi = abs([peripheral.RSSI intValue]);CGFloatci = (rssi -49) / (10*4.);NSString*length = [NSStringstringWithFormat:@"發(fā)現(xiàn)BLT4.0熱點(diǎn):%@,距離:%.1fm",_peripheral,pow(10,ci)];? ? [selfupdateLog:[NSStringstringWithFormat:@"距離:%@", length]];}

(4)發(fā)現(xiàn)服務(wù)和搜索到的Characteristice

//已發(fā)現(xiàn)服務(wù)-(void)peripheral:(CBPeripheral *)peripheraldidDiscoverServices:(NSError *)error{? ? [selfupdateLog:@"發(fā)現(xiàn)服務(wù)."];inti=0;for(CBService *sinperipheral.services) {? ? ? ? [self.nServicesaddObject:s];? ? }for(CBService *sinperipheral.services) {? ? ? ? [selfupdateLog:[NSStringstringWithFormat:@"%d :服務(wù) UUID: %@(%@)",i,s.UUID.data,s.UUID]];? ? ? ? i++;? ? ? ? [peripheraldiscoverCharacteristics:nilforService:s];if([s.UUIDisEqual:[CBUUIDUUIDWithString:@"FF15"]]) {? ? ? ? ? ? BOOL replace = NO;// Match if we have this device from beforefor(inti=0; i < _nDevices.count; i++) {? ? ? ? ? ? ? ? CBPeripheral *p = [_nDevicesobjectAtIndex:i];if([pisEqual:peripheral]) {? ? ? ? ? ? ? ? ? ? [_nDevicesreplaceObjectAtIndex:iwithObject:peripheral];? ? ? ? ? ? ? ? ? ? replace = YES;? ? ? ? ? ? ? ? }? ? ? ? ? ? }if(!replace) {? ? ? ? ? ? ? ? [_nDevicesaddObject:peripheral];? ? ? ? ? ? ? ? [_bluetoothTable reloadData];? ? ? ? ? ? }? ? ? ? }? ? }}//已搜索到Characteristics-(void)peripheral:(CBPeripheral *)peripheraldidDiscoverCharacteristicsForService:(CBService *)serviceerror:(NSError *)error{? ? [selfupdateLog:[NSStringstringWithFormat:@"發(fā)現(xiàn)特征的服務(wù):%@ (%@)",service.UUID.data ,service.UUID]];for(CBCharacteristic *cinservice.characteristics) {? ? ? ? [selfupdateLog:[NSStringstringWithFormat:@"特征 UUID: %@ (%@)",c.UUID.data,c.UUID]];if([c.UUIDisEqual:[CBUUIDUUIDWithString:@"FF01"]]) {? ? ? ? ? ? _writeCharacteristic = c;? ? ? ? }if([c.UUIDisEqual:[CBUUIDUUIDWithString:@"FF02"]]) {? ? ? ? ? ? [_peripheralreadValueForCharacteristic:c];? ? ? ? ? ? [_peripheralsetNotifyValue:YESforCharacteristic:c];? ? ? ? }if([c.UUIDisEqual:[CBUUIDUUIDWithString:@"FF04"]]) {? ? ? ? ? ? [_peripheralreadValueForCharacteristic:c];? ? ? ? }if([c.UUIDisEqual:[CBUUIDUUIDWithString:@"FF05"]]) {? ? ? ? ? ? [_peripheralreadValueForCharacteristic:c];? ? ? ? ? ? [_peripheralsetNotifyValue:YESforCharacteristic:c];? ? ? ? }if([c.UUIDisEqual:[CBUUIDUUIDWithString:@"FFA1"]]) {? ? ? ? ? ? [_peripheral readRSSI];? ? ? ? }? ? ? ? [_nCharacteristicsaddObject:c];? ? }}- (void)centralManager:(CBCentralManager *)centraldidDisconnectPeripheral:(CBPeripheral *)peripheralerror:(NSError *)error {? ? [selfupdateLog:[NSStringstringWithFormat:@"已斷開(kāi)與設(shè)備:[%@]的連接", peripheral.name]];}

(5)獲取外設(shè)發(fā)來(lái)的數(shù)據(jù)

//獲取外設(shè)發(fā)來(lái)的數(shù)據(jù)量窘,不論是read和notify,獲取數(shù)據(jù)都是從這個(gè)方法中讀取。- (void)peripheral:(CBPeripheral *)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error{if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:@"FF02"]]) {? ? ? ? NSData * data = characteristic.value;? ? ? ? Byte * resultByte = (Byte *)[data bytes];for(inti=0;i<[data length];i++)? ? ? ? ? ? printf("testByteFF02[%d] = %d\n",i,resultByte[i]);if(resultByte[1] ==0) {switch(resultByte[0]) {case3:// 加解鎖{if(resultByte[2] ==0) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"撤防成功!!!"];? ? ? ? ? ? ? ? ? ? }elseif(resultByte[2] ==1) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"設(shè)防成功!!!"];? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }break;case4:// 開(kāi)坐桶{if(resultByte[2] ==0) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"關(guān)坐桶成功!!!"];? ? ? ? ? ? ? ? ? ? }elseif(resultByte[2] ==1) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"開(kāi)坐桶成功!!!"];? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }break;case5:// 鎖定電機(jī){if(resultByte[2] ==0) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"解鎖電機(jī)控制器成功!!!"];? ? ? ? ? ? ? ? ? ? }elseif(resultByte[2] ==1) {? ? ? ? ? ? ? ? ? ? ? ? [selfupdateLog:@"鎖定電機(jī)控制器成功!!!"];? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }break;default:break;? ? ? ? ? ? }? ? ? ? }elseif(resultByte[1] ==1) {? ? ? ? ? ? [selfupdateLog:@"未知錯(cuò)誤"];? ? ? ? }elseif(resultByte[1] ==2) {? ? ? ? ? ? [selfupdateLog:@"鑒權(quán)失敗"];? ? ? ? }? ? }if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:@"FF04"]]) {? ? ? ? NSData * data = characteristic.value;? ? ? ? Byte * resultByte = (Byte *)[data bytes];for(inti=0;i<[data length];i++)? ? ? ? ? ? printf("testByteFF04[%d] = %d\n",i,resultByte[i]);if(resultByte[0] ==0) {// 未綁定 -》寫(xiě)鑒權(quán)碼[selfupdateLog:@"當(dāng)前車(chē)輛未綁定氢拥,請(qǐng)鑒權(quán)"];? ? ? ? ? ? [self authentication];// 鑒權(quán)[selfwritePassword:nilnewPw:nil];? ? ? ? }elseif(resultByte[0] ==1) {// 已綁定 -》鑒權(quán)[selfupdateLog:@"當(dāng)前車(chē)輛已經(jīng)綁定蚌铜,請(qǐng)鑒權(quán)"];? ? ? ? ? ? [selfwritePassword:nilnewPw:nil];? ? ? ? }elseif(resultByte[0] ==2) {// 允許綁定[selfupdateLog:@"當(dāng)前車(chē)輛允許綁定"];? ? ? ? }? ? }if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:@"FF05"]]) {? ? ? ? NSData * data = characteristic.value;? ? ? ? Byte * resultByte = (Byte *)[data bytes];for(inti=0;i<[data length];i++)? ? ? ? ? ? printf("testByteFF05[%d] = %d\n",i,resultByte[i]);if(resultByte[0] ==0) {// 設(shè)備加解鎖狀態(tài) 0 撤防? ? 1 設(shè)防[selfupdateLog:@"當(dāng)前車(chē)輛撤防狀態(tài)"];? ? ? ? }elseif(resultByte[0] ==1) {// 設(shè)備加解鎖狀態(tài) 0 撤防? ? 1 設(shè)防[selfupdateLog:@"當(dāng)前車(chē)輛設(shè)防狀態(tài)"];? ? ? ? }? ? }}//中心讀取外設(shè)實(shí)時(shí)數(shù)據(jù)- (void)peripheral:(CBPeripheral *)peripheraldidUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error {if(error) {? ? ? ? NSLog(@"Error changing notification state: %@", error.localizedDescription);? ? }// Notification has startedif(characteristic.isNotifying) {? ? ? ? [peripheralreadValueForCharacteristic:characteristic];? ? }else{// Notification has stopped// so disconnect from the peripheralNSLog(@"Notification stopped on %@.? Disconnecting", characteristic);? ? ? ? [selfupdateLog:[NSStringstringWithFormat:@"Notification stopped on %@.? Disconnecting", characteristic]];? ? ? ? [self.managercancelPeripheralConnection:self.peripheral];? ? }}//用于檢測(cè)中心向外設(shè)寫(xiě)數(shù)據(jù)是否成功-(void)peripheral:(CBPeripheral *)peripheraldidWriteValueForCharacteristic:(CBCharacteristic *)characteristicerror:(NSError *)error{if(error) {? ? ? ? NSLog(@"=======%@",error.userInfo);? ? ? ? [selfupdateLog:[error.userInfo JSONString]];? ? }else{? ? ? ? NSLog(@"發(fā)送數(shù)據(jù)成功");? ? ? ? [selfupdateLog:@"發(fā)送數(shù)據(jù)成功"];? ? }/* When a write occurs, need to set off a re-read of the local CBCharacteristic to update its value */[peripheralreadValueForCharacteristic:characteristic];}

(6)其他輔助性的

#pragma mark - 藍(lán)牙的相關(guān)操作- (IBAction)bluetoothAction:(UIButton*)sender {switch(sender.tag) {case201:? ? ? ? {// 搜索設(shè)備[selfupdateLog:@"正在掃描外設(shè)..."];? ? ? ? ? ? [_activity startAnimating];? ? ? ? ? ? [_manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FF15"]]? options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];doubledelayInSeconds =30.0;? ? ? ? ? ? dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds *NSEC_PER_SEC));? ? ? ? ? ? dispatch_after(popTime, dispatch_get_main_queue(), ^(void){? ? ? ? ? ? ? ? [self.manager stopScan];? ? ? ? ? ? ? ? [_activity stopAnimating];? ? ? ? ? ? ? ? [selfupdateLog:@"掃描超時(shí),停止掃描"];? ? ? ? ? ? });? ? ? ? }break;case202:? ? ? ? {// 連接if(_peripheral && _cbReady) {? ? ? ? ? ? ? ? [_manager connectPeripheral:_peripheral options:nil];? ? ? ? ? ? ? ? _cbReady =NO;? ? ? ? ? ? }? ? ? ? }break;case203:? ? ? ? {// 斷開(kāi)if(_peripheral && !_cbReady) {? ? ? ? ? ? ? ? [_manager cancelPeripheralConnection:_peripheral];? ? ? ? ? ? ? ? _cbReady =YES;? ? ? ? ? ? }? ? ? ? }break;case204:? ? ? ? {// 暫停搜索[self.manager stopScan];? ? ? ? }break;case211:? ? ? ? {// 車(chē)輛上鎖[selflock];? ? ? ? }break;case212:? ? ? ? {// 車(chē)輛解鎖[selfunLock];? ? ? ? }break;case213:? ? ? ? {// 開(kāi)啟坐桶[selfopen];? ? ? ? }break;case214:? ? ? ? {// 立即尋車(chē)[selffind];? ? ? ? }break;default:break;? ? }}-(NSOperationQueue*)queue {if(!_queue) {// 請(qǐng)求隊(duì)列self.queue = [[NSOperationQueuealloc]init];? ? ? ? [self.queue setMaxConcurrentOperationCount:1];? ? }return_queue;}#pragma mark - 命令#pragma mark - 鑒權(quán)-(void)authentication {? ? Byte byte[] = {1,1,2,3,4,5,6,7,8};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:9] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}#pragma mark - 寫(xiě)密碼-(void)writePassword:(NSString*)initialPw newPw:(NSString*)newPw {? ? Byte byte[] = {2,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:17] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}#pragma mark - 車(chē)輛上鎖-(void)lock {? ? Byte byte[] = {3,1};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}#pragma mark - 車(chē)輛解鎖-(void)unLock {? ? Byte byte[] = {3,0};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}#pragma mark - 開(kāi)啟坐桶-(void)open {? ? Byte byte[] = {4,1};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:2] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}#pragma mark - 立即尋車(chē)-(void)find {? ? Byte byte[] = {7};if(_peripheral.state == CBPeripheralStateConnected) {? ? ? ? [_peripheral writeValue:[NSDatadataWithBytes:byte length:1] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];? ? }}-(NSData*)hexString:(NSString*)hexString {intj=0;? ? Byte bytes[20];///3ds key的Byte 數(shù)組锨侯, 128位for(inti=0; i<[hexString length]; i++)? ? {intint_ch;/// 兩位16進(jìn)制數(shù)轉(zhuǎn)化后的10進(jìn)制數(shù)unicharhex_char1 = [hexString characterAtIndex:i];////兩位16進(jìn)制數(shù)中的第一位(高位*16)intint_ch1;if(hex_char1 >='0'&& hex_char1 <='9')? ? ? ? ? ? int_ch1 = (hex_char1-48)*16;//// 0 的Ascll - 48elseif(hex_char1 >='A'&& hex_char1 <='F')? ? ? ? ? ? int_ch1 = (hex_char1-55)*16;//// A 的Ascll - 65elseint_ch1 = (hex_char1-87)*16;//// a 的Ascll - 97i++;unicharhex_char2 = [hexString characterAtIndex:i];///兩位16進(jìn)制數(shù)中的第二位(低位)intint_ch2;if(hex_char2 >='0'&& hex_char2 <='9')? ? ? ? ? ? int_ch2 = (hex_char2-48);//// 0 的Ascll - 48elseif(hex_char1 >='A'&& hex_char1 <='F')? ? ? ? ? ? int_ch2 = hex_char2-55;//// A 的Ascll - 65elseint_ch2 = hex_char2-87;//// a 的Ascll - 97int_ch = int_ch1+int_ch2;NSLog(@"int_ch=%d",int_ch);? ? ? ? bytes[j] = int_ch;///將轉(zhuǎn)化后的數(shù)放入Byte數(shù)組里j++;? ? }NSData*newData = [[NSDataalloc] initWithBytes:bytes length:20];returnnewData;}

在和硬件之間的數(shù)據(jù)發(fā)送和接受,用的都是byte數(shù)組冬殃。最后囚痴,添加一個(gè)存儲(chǔ)已連接過(guò)得設(shè)備

- (void) addSavedDevice:(CFUUIDRef)uuid {NSArray*storedDevices = [[NSUserDefaultsstandardUserDefaults] arrayForKey:@"StoredDevices"];NSMutableArray*newDevices =nil;CFStringRefuuidString =NULL;if(![storedDevices isKindOfClass:[NSArrayclass]]) {NSLog(@"Can't find/create an array to store the uuid");return;? ? }? ? newDevices = [NSMutableArrayarrayWithArray:storedDevices];? ? uuidString =CFUUIDCreateString(NULL, uuid);if(uuidString) {? ? ? ? [newDevices addObject:(__bridgeNSString*)uuidString];CFRelease(uuidString);? ? }/* Store */[[NSUserDefaultsstandardUserDefaults] setObject:newDevices forKey:@"StoredDevices"];? ? [[NSUserDefaultsstandardUserDefaults] synchronize];}- (void) loadSavedDevices {NSArray*storedDevices = [[NSUserDefaultsstandardUserDefaults] arrayForKey:@"StoredDevices"];if(![storedDevices isKindOfClass:[NSArrayclass]]) {NSLog(@"No stored array to load");return;? ? }for(iddeviceUUIDStringinstoredDevices) {if(![deviceUUIDString isKindOfClass:[NSStringclass]])continue;CFUUIDRefuuid =CFUUIDCreateFromString(NULL, (CFStringRef)deviceUUIDString);if(!uuid)continue;? ? ? ? [CBCentralManager retrievePeripherals:[NSArrayarrayWithObject:(__bridgeid)uuid]];CFRelease(uuid);? ? }}//And the delegate function for the Retrieve Peripheral- (void) centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray*)peripherals {? ? CBPeripheral *peripheral;/* Add to list. */for(peripheralinperipherals) {? ? ? ? [central connectPeripheral:peripheral options:nil];? ? }} - (void) centralManager:(CBCentralManager *)central didRetrievePeripheral:(CBPeripheral *)peripheral {? ? [central connectPeripheral:peripheral options:nil];}

后記

最主要是用UUID來(lái)確定你要干的事情,特征和服務(wù)的UUID都是外設(shè)定義好的审葬。我們只需要讀取深滚,確定你要讀取什么的時(shí)候,就去判斷UUID是否相符涣觉。 一般來(lái)說(shuō)我們使用的iPhone都是做centralManager的痴荐,藍(lán)牙模塊是peripheral的,所以我們是want datas官册,需要接受數(shù)據(jù)生兆。

1.判斷狀態(tài)為powerOn,然后執(zhí)行掃描

2.停止掃描膝宁,連接外設(shè)

3.連接成功鸦难,尋找服務(wù)

4.在服務(wù)里尋找特征

5.為特征添加通知

5.通知添加成功,那么就可以實(shí)時(shí)的讀取value[也就是說(shuō)只要外設(shè)發(fā)送數(shù)據(jù)[一般外設(shè)的頻率為10Hz]员淫,代理就會(huì)調(diào)用此方法]合蔽。

6.處理接收到的value,[hex值介返,得轉(zhuǎn)換] 之后就自由發(fā)揮了辈末,在這期間都是通過(guò)代理來(lái)實(shí)現(xiàn)的,也就是說(shuō)你只需要處理你想要做的事情映皆,代理會(huì)幫你調(diào)用方法挤聘。[別忘了添加代理]

2015-07-28 更

關(guān)于write我這里還有些注意的地方要強(qiáng)調(diào)!M背埂W槿ァ!

并不是每一個(gè)Characteristic都可以通過(guò)回調(diào)函數(shù)來(lái)查看它寫(xiě)入狀態(tài)的步淹。就比如針對(duì) immediateAlertService(1802) 的 alertLevelCharacteristic(2A06)从隆,就是一個(gè)不能有response的Characteristic。剛開(kāi)始我就一直用CBCharacteristicWriteType.WithResponse來(lái)進(jìn)行寫(xiě)入始終不成功缭裆,郁悶壞了键闺,最后看到每個(gè)Characteristic還有個(gè)屬性值是指示這個(gè)的,我將每個(gè)Characteristic打印出來(lái)有如下信息:

immediateAlertService Discover characteristiclinkLossAlertService Discover characteristic

這個(gè)的properties是什么剛開(kāi)始不知道澈驼,覺(jué)得他沒(méi)意義辛燥,后面才注意到properties是Characteristic的一個(gè)參數(shù),具體解釋如下:

DeclarationSWIFTstruct CBCharacteristicProperties :RawOptionSetType{? ? init(_value: UInt)? ? var value: UInt? ? static var Broadcast: CBCharacteristicProperties { get }staticvarRead:CBCharacteristicProperties{ get }staticvarWriteWithoutResponse:CBCharacteristicProperties{ get }staticvarWrite:CBCharacteristicProperties{ get }staticvarNotify:CBCharacteristicProperties{ get }staticvarIndicate:CBCharacteristicProperties{ get }staticvarAuthenticatedSignedWrites:CBCharacteristicProperties{ get }staticvarExtendedProperties:CBCharacteristicProperties{ get }staticvarNotifyEncryptionRequired:CBCharacteristicProperties{ get }staticvarIndicateEncryptionRequired:CBCharacteristicProperties{ get }}OBJECTIVE-Ctypedefenum{? CBCharacteristicPropertyBroadcast =0x01,? CBCharacteristicPropertyRead =0x02,? CBCharacteristicPropertyWriteWithoutResponse =0x04,? CBCharacteristicPropertyWrite =0x08,? CBCharacteristicPropertyNotify =0x10,? CBCharacteristicPropertyIndicate =0x20,? CBCharacteristicPropertyAuthenticatedSignedWrites =0x40,? CBCharacteristicPropertyExtendedProperties =0x80,? CBCharacteristicPropertyNotifyEncryptionRequired =0x100,? CBCharacteristicPropertyIndicateEncryptionRequired =0x200,}CBCharacteristicProperties;

可以看到0x04對(duì)應(yīng)的是CBCharacteristicPropertyWriteWithoutResponse

0x0A對(duì)應(yīng)的是CBCharacteristicPropertyNotify

所以 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06)是不能用CBCharacteristicWriteType.WithRespons進(jìn)行寫(xiě)入,只能用CBCharacteristicWriteType.WithOutRespons挎塌。這樣在以后的開(kāi)發(fā)中可以對(duì)每個(gè)Characteristic的這個(gè)參數(shù)進(jìn)行檢查再進(jìn)行設(shè)置徘六。

最后講一下關(guān)于藍(lán)牙綁定的過(guò)程,在iOS中榴都,沒(méi)有講當(dāng)綁定的過(guò)程待锈,直接就是掃描、連接嘴高、交互竿音。從而很多人會(huì)認(rèn)為,連接就是綁定了拴驮,其實(shí)不然春瞬。在iOS開(kāi)發(fā)中,連接并沒(méi)有完成綁定莹汤,在網(wǎng)上找到了個(gè)很好的解釋:

you cannot initiate pairing from the iOS central side. Instead, you have to read/write a characteristic value,

and then let your peripheral respond with an "Insufficient Authentication" error.

iOS will then initiate pairing, will store the keys for later use (bonding) and encrypts the link. As far as I know,

it also caches discovery information, so that future connections can be set up faster.

就是當(dāng)發(fā)生讀寫(xiě)交互時(shí)快鱼,系統(tǒng)在會(huì)和外設(shè)進(jìn)行綁定操作!!!

2016-02-20 更

ios藍(lán)牙如何獲取廣播包數(shù)據(jù)

如題颠印,手機(jī)作為主設(shè)備纲岭,在使用CoreBluetooth時(shí)候,想獲取藍(lán)牙的數(shù)據(jù)廣播包线罕。在使用

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)aPeripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

方法時(shí)候獲取的advertisementData打印出來(lái)只有

******kCBAdvDataIsConnectable****kCBAdvDataLocalName****kCBAdvDataManufacturerData**

三個(gè)屬性對(duì)應(yīng)的值止潮,但這并非廣播包的數(shù)據(jù)。例如安卓可以通過(guò)scandata來(lái)獲取到廣播包的值钞楼,那么iOS這邊我應(yīng)該怎么做呢喇闸?

好像蘋(píng)果這邊禁止讀取這種廣播內(nèi)容的的,真要的話你可以讓硬件那邊把數(shù)據(jù)做到kCBAdvDataManufacturerData這個(gè)字段里面询件。

Demo地址:一個(gè)藍(lán)牙4.0的智能硬件Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末燃乍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宛琅,更是在濱河造成了極大的恐慌刻蟹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘿辟,死亡現(xiàn)場(chǎng)離奇詭異舆瘪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)红伦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)英古,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人昙读,你說(shuō)我怎么就攤上這事召调。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵某残,是天一觀的道長(zhǎng)国撵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)玻墅,這世上最難降的妖魔是什么介牙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮澳厢,結(jié)果婚禮上环础,老公的妹妹穿的比我還像新娘。我一直安慰自己剩拢,他們只是感情好线得,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著徐伐,像睡著了一般贯钩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上办素,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天角雷,我揣著相機(jī)與錄音,去河邊找鬼性穿。 笑死勺三,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的需曾。 我是一名探鬼主播吗坚,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼呆万!你這毒婦竟也來(lái)了商源?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谋减,失蹤者是張志新(化名)和其女友劉穎牡彻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逃顶,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讨便,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了以政。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霸褒。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盈蛮,靈堂內(nèi)的尸體忽然破棺而出废菱,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布殊轴,位于F島的核電站衰倦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏旁理。R本人自食惡果不足惜樊零,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望孽文。 院中可真熱鬧驻襟,春花似錦、人聲如沸芋哭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)减牺。三九已至豌习,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拔疚,已是汗流浹背肥隆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留草雕,地道東北人巷屿。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓固以,卻偏偏與公主長(zhǎng)得像墩虹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子憨琳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容