日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS 蓝牙开发和注意点

發(fā)布時(shí)間:2025/4/5 编程问答 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS 蓝牙开发和注意点 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

  • 藍(lán)牙傳輸所用的框架是<CoreBluetooth/CoreBluetooth.h>
  • 藍(lán)牙連接需要中心管理者和外部設(shè)備,我們所做的開發(fā)基本是圍繞中心管理來的;
  • 藍(lán)牙設(shè)備發(fā)過來的每個(gè)數(shù)據(jù)包,為了保證數(shù)據(jù)在傳輸?shù)臅r(shí)候沒有丟失,一般需要包頭,包尾,校驗(yàn)和
  • 有很多藍(lán)牙協(xié)議很復(fù)雜,需要把數(shù)據(jù)轉(zhuǎn)化成二進(jìn)制進(jìn)行轉(zhuǎn)化解析,對于高字節(jié),低字節(jié),小端模式,大端模式,符號(hào)位,位運(yùn)算這些基本概念需要了解清楚

1.關(guān)于Mac地址的獲取

自iOS7之后,蘋果不支持獲取Mac地址,只能用UUID來標(biāo)識(shí)設(shè)備,要注意的是同一個(gè)設(shè)備在不同手機(jī)上顯示的UUID不相同,但有的設(shè)備可以通過 “180A”這個(gè)服務(wù)來發(fā)現(xiàn)特征,再來讀取 “2A23”這個(gè)特征值,可以獲得Mac地址。如果你的藍(lán)牙設(shè)備不支持這樣獲取,你可以跟硬件工程師溝通,來獲得Mac地址,添加一個(gè)獲取地址命令或者增加一個(gè)含地址的特征值都可以很容易的獲取。上面獲取地址的前提都是需要先建立連接,如果一定要在掃描的時(shí)候獲得Mac地址,讓硬件工程師把數(shù)據(jù)寫入廣播包里,看是否可行;

2.藍(lán)牙連接流程

如果你不是新手,又不想浪費(fèi)時(shí)間,請直接看第三點(diǎn) 注意點(diǎn),核心部分

  • 建立中心設(shè)備管理者
  • 掃描外設(shè)
  • 連接外設(shè)
  • 掃描外設(shè)中的服務(wù)
  • 掃描外設(shè)中的特征
  • 訂閱或讀取特征值
  • 獲取外設(shè)中的數(shù)據(jù)

建立中心設(shè)備管理者

// 創(chuàng)建之后會(huì)馬上檢查藍(lán)牙的狀態(tài),nil默認(rèn)為主線程 self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]

藍(lán)牙線程沒必要去開異步線程,在主線程消耗不了什么性能

掃描外設(shè)

// 藍(lán)牙狀態(tài)發(fā)生改變,這個(gè)方法一定要實(shí)現(xiàn) - (void)centralManagerDidUpdateState:(CBCentralManager *)central {// 藍(lán)牙狀態(tài)可用if (central.state == CBCentralManagerStatePoweredOn) {// 如果藍(lán)牙支持后臺(tái)模式,一定要指定服務(wù),否則在后臺(tái)斷開連接不上,如果不支持,可設(shè)為nil, option里的CBCentralManagerScanOptionAllowDuplicatesKey默認(rèn)為NO, 如果設(shè)置為YES,允許搜索到重名,會(huì)很耗電[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:nil];} }

連接外設(shè)

/*** 發(fā)現(xiàn)設(shè)備* @param peripheral 設(shè)備* @param advertisementData 廣播內(nèi)容* @param RSSI 信號(hào)強(qiáng)度*/ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {// 判斷是否是你需要連接的設(shè)備if ([peripheral.name isEqualToString:kPeripheralName]) {peripheral.delegate = self;// 一定要記得把外設(shè)保存起來self.selectedPeripheral = peripheral;// 開始連接設(shè)備[self.centralManager connectPeripheral:self.selectedPeripheral options:nil];} }

掃描外設(shè)中的服務(wù)

/*** 已經(jīng)連接上設(shè)備*/ - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {// 停止掃描[self.centralManager stopScan];// 發(fā)現(xiàn)服務(wù)[self.selectedPeripheral discoverServices:nil]; }

掃描外設(shè)中的特征

/*** 已經(jīng)發(fā)現(xiàn)服務(wù)*/ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {for (CBService *service in peripheral.services) {if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {// 根據(jù)你要的那個(gè)服務(wù)去發(fā)現(xiàn)特性[self.selectedPeripheral discoverCharacteristics:nil forService:service];}// 這里我是根據(jù) 180A 用來獲取Mac地址,沒什么實(shí)際作用,可刪掉if ([service.UUID isEqual:[CBUUID UUIDWithString:@"180A"]]) {[self.selectedPeripheral discoverCharacteristics:nil forService:service];}} }

訂閱或讀取特征值

/*** 已經(jīng)發(fā)現(xiàn)特性*/ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {for (CBCharacteristic *characteristic in service.characteristics) {if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A23"]]) {// 這里是讀取Mac地址, 可不要, 數(shù)據(jù)固定, 用readValueForCharacteristic, 不用setNotifyValue:setNotifyValue[self.selectedPeripheral readValueForCharacteristic:characteristic];}if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {// 訂閱特性,當(dāng)數(shù)據(jù)頻繁改變時(shí),一般用它, 不用readValueForCharacteristic[peripheral setNotifyValue:YES forCharacteristic:characteristic];// 獲取電池電量unsigned char send[4] = {0x5d, 0x08, 0x01, 0x3b};NSData *sendData = [NSData dataWithBytes:send length:4];// 這里的type類型有兩種 CBCharacteristicWriteWithResponse CBCharacteristicWriteWithoutResponse,它的屬性枚舉可以組合[self.selectedPeripheral writeValue:sendData forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];/*characteristic 屬性typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {CBCharacteristicPropertyBroadcast = 0x01,CBCharacteristicPropertyRead = 0x02,CBCharacteristicPropertyWriteWithoutResponse = 0x04,CBCharacteristicPropertyWrite = 0x08,CBCharacteristicPropertyNotify = 0x10,CBCharacteristicPropertyIndicate = 0x20,CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,CBCharacteristicPropertyExtendedProperties = 0x80,CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200};*/NSLog(@"%@",characteristic);// 打印結(jié)果為 <CBCharacteristic: 0x1702a2a00, UUID = FFF6, properties = 0x16, value = (null), notifying = NO>// 我的結(jié)果 為 0x16 (0x08 & 0x16)結(jié)果不成立, (0x04 & 0x16)結(jié)果成立,那寫入類型就是 CBCharacteristicPropertyWriteWithoutResponse}} }

獲取外設(shè)中的數(shù)據(jù)

/*** 數(shù)據(jù)更新的回調(diào)*/ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {// 這里收到的數(shù)據(jù)都是16進(jìn)制,有兩種轉(zhuǎn)換,一種就直接轉(zhuǎn)字符串,另一種是轉(zhuǎn)byte數(shù)組,看用哪種方便// 直接轉(zhuǎn)字符串NSString *orStr = characteristic.value.description;NSString *str = [orStr substringWithRange:NSMakeRange(1, orStr.length - 2)];NSString *dataStr = [str stringByReplacingOccurrencesOfString:@" " withString:@""];NSLog(@"dataStr = %@",dataStr);// 轉(zhuǎn)Byte數(shù)組Byte *byte = (Byte *)characteristic.value.bytes;//_______________________________________________________________________________________________________________// 解析你的協(xié)議,附幾個(gè)解協(xié)議或許能用到的函數(shù) }

設(shè)備連接斷開

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {// 讓它自動(dòng)重連[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:nil]; }

這是系統(tǒng)代理方法,如果要主動(dòng)斷開需要調(diào)用 - (void)cancelPeripheralConnection:(CBPeripheral *)peripheral; 這個(gè)方法

寫入數(shù)據(jù)成功的回調(diào)

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {// 讀取數(shù)據(jù)[self.selectedPeripheral readValueForCharacteristic:characteristic]; }

如果類型是CBCharacteristicWriteWithoutResponse,不會(huì)走這個(gè)方法;

3.注意點(diǎn),核心部分,請仔細(xì)看

  • 做藍(lán)牙前一定要去商城下個(gè)LightBlue,一個(gè)設(shè)備有很多服務(wù),服務(wù)中又有很多特性,特性中又分讀的,寫的等,有了LightBlue,你可以很快的找到你需要的特性;


    LightBlue截圖


    從上圖中我們可以清晰的看到每個(gè)服務(wù)中又多少個(gè)特性,特性的屬性Read、Write、Write Without Response、Notify等也標(biāo)明的很清楚,

  • 一般的藍(lán)牙都要支持重連和后臺(tái)運(yùn)行,如果掃描設(shè)備的時(shí)候,用這個(gè)方法- (void)scanForPeripheralsWithServices:options:沒有指定特定的服務(wù),而是用nil代替,設(shè)備在后臺(tái)斷開的時(shí)候是不會(huì)重連的;

  • 藍(lán)牙是可以同時(shí)連接多個(gè)外部設(shè)備

  • 關(guān)于readValueForCharacteristic和 setNotifyValue:forCharacteristic: 的區(qū)別, readValueForCharacteristic適合用來讀取數(shù)據(jù)不怎么更新的特征值, 如果獲取的數(shù)據(jù)是經(jīng)常更新的,那就 一定要用setNotifyValue:forCharacteristic:來訂閱這個(gè)特征;

  • 當(dāng)我們寫入命令時(shí)writeValue:forCharacteristic:type:,這個(gè)type類型到時(shí)是用CBCharacteristicWriteWithResponse還是用CBCharacteristicWriteWithoutResponse會(huì)有疑惑,先看一下特性屬性的枚舉,它們是可以組合的

    /*typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {CBCharacteristicPropertyBroadcast = 0x01,CBCharacteristicPropertyRead = 0x02,CBCharacteristicPropertyWriteWithoutResponse = 0x04,CBCharacteristicPropertyWrite = 0x08,CBCharacteristicPropertyNotify = 0x10,CBCharacteristicPropertyIndicate = 0x20,CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,CBCharacteristicPropertyExtendedProperties = 0x80,CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200};

    再來看看我打印的兩個(gè)特征值,第一個(gè)是獲取Mac地址的特性,另一個(gè)是獲取數(shù)據(jù)的特性
    <CBCharacteristic: 0x1700b8ae0, UUID = System ID, properties = 0x2, value = (null), notifying = NO>
    <CBCharacteristic: 0x1702a2a00, UUID = FFF6, properties = 0x16, value = (null), notifying = NO>
    第一個(gè)0x2對應(yīng)只可讀, 第二個(gè) (0x16 & 0x08)不成立,(0x16 & 0x04)成立,所以用CBCharacteristicWriteWithoutResponse,而且這個(gè)特征值還可讀,可以通知

  • 代理方法- (void)centralManagerDidUpdateState:(CBCentralManager *)central;一定要調(diào)用,否則會(huì)報(bào)錯(cuò),這個(gè)方法只要設(shè)置中心設(shè)備的代理之后,就一定會(huì)走,我們最開始的掃描外設(shè)應(yīng)放在這個(gè)方法里;

  • 對于是否要單獨(dú)創(chuàng)建一個(gè)工具類來獲取藍(lán)牙數(shù)據(jù),如果只是一個(gè)界面需要用到藍(lán)牙數(shù)據(jù),我覺得完全沒必要,如果是多個(gè)界面的話,最好還是創(chuàng)建一個(gè)工具類。

  • 如果藍(lán)牙支持要支持后臺(tái)模式,只需要去把藍(lán)牙后臺(tái)模式打開


    后臺(tái)運(yùn)行藍(lán)牙


    記住只要勾選Uses Bluetooth LE accessories就行了,別勾選Acts As a Bluetooth LE accessory,除非你把你的手機(jī)當(dāng)做外部設(shè)備使用;

  • 簡單又詳細(xì)的Demo地址



    作者:alenpaulkevin
    鏈接:http://www.jianshu.com/p/0ccfd53fc559
    來源:簡書
    著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

    轉(zhuǎn)載于:https://www.cnblogs.com/Ghosgt/p/7779463.html

    總結(jié)

    以上是生活随笔為你收集整理的iOS 蓝牙开发和注意点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。