iOS藍(lán)牙開發(fā)(CoreBluetooth)

目前在iOS中藍(lán)牙開發(fā)框架主要有以下幾種

  • GameKit.framework:iOS7之前的藍(lán)牙通訊框架,從iOS7開始過(guò)期.
  • MultipeerConnectivity.framework:iOS7開始引入的新的藍(lán)牙通訊開發(fā)框架岳守,用于取代GameKit。
  • CoreBluetooth.framework:功能強(qiáng)大的藍(lán)牙開發(fā)框架,要求設(shè)備必須支持藍(lán)牙4.0鼓择。
  • 前兩個(gè)框架使用起來(lái)比較簡(jiǎn)單兑宇,但是缺點(diǎn)也比較明顯:僅僅支持iOS設(shè)備,傳輸內(nèi)容僅限于沙盒或者照片庫(kù)中用戶選擇的文件邢隧,并且第一個(gè)框架只能在同一個(gè)應(yīng)用之間進(jìn)行傳輸(一個(gè)iOS設(shè)備安裝應(yīng)用A修档,另一個(gè)iOS設(shè)備上安裝應(yīng)用B是無(wú)法傳輸?shù)模oreBluetooth就擺脫了這些束縛府框,它不再局限于iOS設(shè)備之間進(jìn)行傳輸吱窝,你可以通過(guò)iOS設(shè)備向Android讥邻、Windows Phone以及其他安裝有藍(lán)牙4.0芯片的智能設(shè)備傳輸,因此也是目前智能家居院峡、無(wú)線支付等熱門智能設(shè)備所推崇的技術(shù)兴使。本文主要介紹CoreBluetooth的相關(guān)開發(fā)流程.

CoreBluetooth開發(fā)模式

CoreBluetooth設(shè)計(jì)類似于客戶端-服務(wù)器端的設(shè)計(jì),peripheral和central, 可以理解成外設(shè)和中心照激。對(duì)應(yīng)他們分別有一組相關(guān)的API和類.


CoreBluetooth架構(gòu)
  • 左側(cè)叫做中心模式发魄,以app作為中心,連接其他的外設(shè)的俩垃,而右側(cè)稱為外設(shè)模式励幼,使用手機(jī)作為外設(shè)別其他中心設(shè)備操作的場(chǎng)景。
  • 服務(wù)和特征口柳,特征的屬性(service and characteristic):
    藍(lán)牙設(shè)備添加若干服務(wù)苹粟,服務(wù)內(nèi)添加若干特征,特征就是具體鍵值對(duì)跃闹,提供對(duì)數(shù)據(jù)的讀取和寫嵌削。藍(lán)牙中心和外設(shè)數(shù)據(jù)的交換基于服務(wù)的特征.


    外設(shè)和服務(wù)特征的關(guān)系

中心的開發(fā)

  • 流程
    <pre>
  1. 建立中心角色
  2. 掃描外設(shè)(discover)
  3. 連接外設(shè)(connect)
  4. 掃描外設(shè)中的服務(wù)和特征(discover)
    • 4.1 獲取外設(shè)的services
    • 4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值,獲取 Characteristics的Descriptor和Descriptor的值
  5. 與外設(shè)做數(shù)據(jù)交互(explore and interact)
  6. 訂閱Characteristic的通知
  7. 斷開連接(disconnect)
    </pre>
  • 步驟
    CoreBluetooth中不管是中心還是外設(shè)的開發(fā),均是上面的流程,通過(guò)一步步的代理回調(diào)實(shí)現(xiàn)的,按照流程跟著走,一步一步實(shí)現(xiàn)代理.
    <pre>
    //初始化
    _centralManager = [[CBCentralManager alloc] initWithDelegate:self
    queue:nil
    options:@{CBCentralManagerOptionRestoreIdentifierKey:kRestoreIdentifierKey}];
    //監(jiān)聽(tīng)中心設(shè)備狀態(tài)
    -(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    if (central.state == CBCentralManagerStatePoweredOn) {
    [self writeToLogWithText:@"中心設(shè)備已打開"];
    [_centralManager scanForPeripheralsWithServices:nil options:nil];
    } //中心設(shè)備CBCentralManagerStatePoweredOn狀態(tài)下就可以開始搜索外設(shè)了
    }
    -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    //搜索到指定的外設(shè)就可以開始連接外設(shè)了
    [_centralManager connectPeripheral:peripheral options:nil];
    }
    -(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    //連接成功后開始搜索服務(wù)
    [peripheral discoverServices:nil];
    }
    -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    //搜索服務(wù)成功后查找指定服務(wù)中的特征
    [peripheral discoverCharacteristics:nil forService:service];
    }
    -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error{
    //發(fā)現(xiàn)可用特征后,就可以進(jìn)行相應(yīng)的操作了,主要有以下三種
    //情景一:讀取
    if (characteristic.properties & CBCharacteristicPropertyRead) {
    if ([characteristic.UUID.UUIDString isEqualToString:kReadUUID]) {
    [peripheral readValueForCharacteristic:characteristic];
    if (characteristic.value) {
    NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    NSLog(@"讀取到特征值:%@",value);
    }
    }
    }

      //情景二:通知
      if (characteristic.properties & CBCharacteristicPropertyNotify) {
          if ([characteristic.UUID.UUIDString isEqualToString:kNotifyUUID] || [characteristic.UUID.UUIDString isEqualToString:kWriteUUID]) {
              _curCharacter = characteristic;
              [peripheral setNotifyValue:YES forCharacteristic:characteristic];
              [self writeToLogWithText:@"已訂閱特征通知"];
          }
      }
      
      //情景二:寫數(shù)據(jù)
      if (characteristic.properties & CBCharacteristicPropertyWrite) {
          if ([characteristic.UUID.UUIDString isEqualToString:kWriteUUID]) {
              [peripheral writeValue:[@"hello,外設(shè)" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
              [self writeToLogWithText:@"寫數(shù)據(jù)給外設(shè)"];
              
              _curPeripherals = peripheral;
              _curCharacter = characteristic;
          }
      }
    

}
//根據(jù)不同的場(chǎng)景,會(huì)調(diào)用以下三個(gè)方法
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error;
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error;
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error;
}
</pre>

外設(shè)的開發(fā)

  • 流程
    <pre>
    1. 打開peripheralManager望艺,設(shè)置peripheralManager的委托
  1. 創(chuàng)建characteristics苛秕,characteristics的description 創(chuàng)建service,把characteristics添加到service中找默,再把service添加到peripheralManager中
  2. 開啟廣播advertising
  3. 對(duì)central的操作進(jìn)行響應(yīng)
    • 4.1 讀characteristics請(qǐng)求
    • 4.2 寫characteristics請(qǐng)求
    • 4.4 訂閱和取消訂閱characteristics
      </pre>
  • 步驟
    <pre>
    //初始化
    _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
    //啟動(dòng)外設(shè)
    -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    switch (peripheral.state) {
    case CBPeripheralManagerStatePoweredOn:
    //CBPeripheralManagerStatePoweredOn下添加服務(wù)和特征
    [self setupService];
    }
    //創(chuàng)建服務(wù),特征并添加服務(wù)到外圍設(shè)備
    -(void)setupService{

    //可通知的特征
    // CBUUID *characteristicUUID = [CBUUID UUIDWithString:kNotifyUUID];
    // _characteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];

    //可讀寫的特征
    CBUUID *UUID2 = [CBUUID UUIDWithString:kWriteUUID];
    _characteristic = [[CBMutableCharacteristic alloc] initWithType:UUID2 properties:CBCharacteristicPropertyWrite|CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsWriteEncryptionRequired];
    //
    //只讀的特征
    // CBUUID *UUID3 = [CBUUID UUIDWithString:kReadUUID];
    // NSData *characteristicValue = [@"aaron才" dataUsingEncoding:NSUTF8StringEncoding];
    // _characteristic = [[CBMutableCharacteristic alloc] initWithType:UUID3 properties:CBCharacteristicPropertyRead value:characteristicValue permissions:CBAttributePermissionsReadable];

    CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
    _service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES];
    [_service setCharacteristics:@[_characteristic]];

    [_peripheralManager addService:_service];
    }
    //添加服務(wù)后開始廣播,等待中心設(shè)備的連接
    -(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(nullable NSError *)error{
    NSDictionary *dict = @{CBAdvertisementDataLocalNameKey:kPeripheralName};
    [_peripheralManager startAdvertising:dict];
    [self writeToLogWithText:@"向外圍設(shè)備添加了服務(wù)"];
    }
    根據(jù)中心設(shè)備的響應(yīng),外設(shè)在代理中收到中心發(fā)來(lái)的信息,
    //訂閱特征
    -(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;
    //取消訂閱
    -(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;
    //中心設(shè)備讀外設(shè)數(shù)據(jù)
    -(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request;
    //收到中心寫來(lái)的數(shù)據(jù)
    -(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests;
    </pre>

UIBackgroundModes下的藍(lán)牙數(shù)據(jù)傳輸

CoreBluetooth提供了非常友好的Background支持.按一下步驟,經(jīng)過(guò)測(cè)試,app進(jìn)入后臺(tái)后,也能收到外設(shè)特征更新的值,據(jù)WWDC2013視頻介紹,就算因?yàn)閮?nèi)存緊張,app在后臺(tái)被殺掉,系統(tǒng)也會(huì)自動(dòng)幫我們重新啟動(dòng)app進(jìn)行藍(lán)牙數(shù)據(jù)傳輸,不過(guò)這個(gè)就沒(méi)測(cè)試到,不知道有沒(méi)有人做過(guò)這方便的研究.

  • 設(shè)置info.plist
    

<pre>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>bluetooth-peripheral</string>
</array>
</pre>

  • 初始化方式中添加``options:@{CBCentralManagerOptionRestoreIdentifierKey:kRestoreIdentifierKey}``
    

<pre>
_centralManager = [[CBCentralManager alloc] initWithDelegate:self
queue:nil
options:@{CBCentralManagerOptionRestoreIdentifierKey:kRestoreIdentifierKey}];
</pre>

<pre>

  • (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict{

// NSArray *scanServices = dict[CBCentralManagerRestoredStateScanServicesKey];
// NSArray *scanOptions = dict[CBCentralManagerRestoredStateScanOptionsKey];

NSArray *peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey];
for (CBPeripheral *peripheral in peripherals) {
    [self.peripherals addObject:peripheral];
    peripheral.delegate = self;
}

}
</pre>

<pre>

  • (void)centralManagerDidUpdateState:(CBCentralManager *)central{

    if (central.state == CBCentralManagerStatePoweredOn) {
    [self writeToLogWithText:@"中心設(shè)備已打開"];
    [_centralManager scanForPeripheralsWithServices:nil options:nil];

      //03,檢查是否restore connected peripherals
      for (CBPeripheral *peripheral in _peripherals) {
          if (peripheral.state == CBPeripheralStateConnected) {
              NSUInteger serviceIdx = [peripheral.services indexOfObjectPassingTest:^BOOL(CBService * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                  return [obj.UUID isEqual:kServiceUUID];
              }];
              
              if (serviceIdx == NSNotFound) {
                  [peripheral discoverServices:@[kServiceUUID]];
                  continue;
              }
              
              CBService *service = peripheral.services[serviceIdx];
              NSUInteger charIdx = [service.characteristics indexOfObjectPassingTest:^BOOL(CBCharacteristic * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                  return [obj.UUID isEqual:kNotifyUUID];
              }];
              
              if (charIdx == NSNotFound) {
                  [peripheral discoverCharacteristics:@[kNotifyUUID] forService:service];
                  continue;
              }
              
              CBCharacteristic *characteristic = service.characteristics[charIdx];
              if (!characteristic.isNotifying) {
                  [peripheral setNotifyValue:YES forCharacteristic:characteristic];
              }
          }
      }
    

    }else{
    [_peripherals removeAllObjects];
    }
    }
    </pre>

<pre>

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    NSArray *peripheralManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothPeripheralsKey];
    NSArray *centraManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey];

    for (NSString *identifier in centraManagerIdentifiers) {
    if ([identifier isEqualToString:kRestoreIdentifierKey]) {

      }
    

    }

    return YES;
    }
    </pre>

Demo

不動(dòng)手寫代碼的學(xué)框架都是耍流氓,為了更好的學(xué)習(xí),我也是自己都敲了一遍代碼,前文中的三種場(chǎng)景以及后臺(tái)模式都實(shí)現(xiàn)了,可以實(shí)現(xiàn)中心設(shè)備和外設(shè)之前的訂閱特征,讀寫數(shù)據(jù)等功能.希望大家都交流.下面是傳送門以及界面展示??
github傳送門 CoreBluetoothDemo

主界面

![中心設(shè)備]IMG_3660.PNG](http://upload-images.jianshu.io/upload_images/1093584-e66b42d6c1c7133f.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

外設(shè)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艇劫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惩激,更是在濱河造成了極大的恐慌港准,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咧欣,死亡現(xiàn)場(chǎng)離奇詭異浅缸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)魄咕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門衩椒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人哮兰,你說(shuō)我怎么就攤上這事毛萌。” “怎么了喝滞?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵阁将,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我右遭,道長(zhǎng)做盅,這世上最難降的妖魔是什么缤削? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吹榴,結(jié)果婚禮上亭敢,老公的妹妹穿的比我還像新娘。我一直安慰自己图筹,他們只是感情好帅刀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著远剩,像睡著了一般扣溺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓜晤,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天锥余,我揣著相機(jī)與錄音,去河邊找鬼活鹰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛只估,可吹牛的內(nèi)容都是我干的志群。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蛔钙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锌云!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起吁脱,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桑涎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后兼贡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攻冷,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年遍希,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了等曼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凿蒜,死狀恐怖禁谦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情废封,我是刑警寧澤州泊,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站漂洋,受9級(jí)特大地震影響遥皂,放射性物質(zhì)發(fā)生泄漏力喷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一渴肉、第九天 我趴在偏房一處隱蔽的房頂上張望冗懦。 院中可真熱鬧,春花似錦仇祭、人聲如沸披蕉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)没讲。三九已至,卻和暖如春礁苗,著一層夾襖步出監(jiān)牢的瞬間爬凑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工试伙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嘁信,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓疏叨,卻偏偏與公主長(zhǎng)得像潘靖,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚤蔓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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

  • 這里我們具體說(shuō)明一下中心模式的應(yīng)用場(chǎng)景卦溢。主設(shè)備(手機(jī)去掃描連接外設(shè),發(fā)現(xiàn)外設(shè)服務(wù)和屬性秀又,操作服務(wù)和屬性的應(yīng)用单寂。一般...
    丶逝水流年閱讀 2,260評(píng)論 3 4
  • 概念 iOS開發(fā)中,談到藍(lán)牙現(xiàn)在基本最常使用的框架就是CoreBluetooth框架了吐辙,使用該框架可以iOS設(shè)備與...
    軟件iOS開發(fā)閱讀 1,135評(píng)論 1 4
  • 本文主要以藍(lán)牙4.0做介紹,因?yàn)楝F(xiàn)在iOS能用的藍(lán)牙也就是只僅僅4.0的設(shè)備 用的庫(kù)就是core bluetoot...
    暮雨飛煙閱讀 840評(píng)論 0 2
  • 首先進(jìn)一則廣告: 藍(lán)牙技術(shù)聯(lián)盟(Bluetooth SIG)2010年7月7日宣布宣决,正式采納藍(lán)牙4.0核心規(guī)范(B...
    L澤閱讀 1,445評(píng)論 3 4
  • 深夜里的我變一條大魚,在深海藍(lán)做噩夢(mèng)的孤獨(dú)的鯨昏苏。 我在夜里醒來(lái)疲扎,因?yàn)樨瑝?mèng)的緣故。夢(mèng)見(jiàn)家里邊去世了好多人捷雕,夢(mèng)見(jiàn)妹妹不...
    橘汁兒閱讀 681評(píng)論 0 1