iOS關(guān)于藍(lán)牙框架BLE的開發(fā)--基礎(chǔ)用法(上)

基礎(chǔ)用法先說明一下,自己創(chuàng)建一個(gè)叫BluetoothManager的單例,在頭文件BluetoothManager.h導(dǎo)入系統(tǒng)藍(lán)牙框架,分別創(chuàng)建幾個(gè)數(shù)組,在使用時(shí)調(diào)用:
#import <CoreBluetooth/CoreBluetooth.h>
@interface BluetoothManager : NSObject
@property (nonatomic, strong) NSMutableArray *findPeripherals; //查找到設(shè)備(不包含用戶列表里的設(shè)備)
@property (nonatomic, strong) NSMutableArray *connectPeripherals; //連接上的設(shè)備
@property (nonatomic, strong) CBCentralManager *cbCentralManager;

/**
 單例實(shí)現(xiàn)方法
 */
+ (BluetoothManager *)share;
@end

在.m文件里面創(chuàng)建單例,并且添加藍(lán)牙模塊的協(xié)議,并為簽訂代理:
#import "BluetoothManager.h"

@interface BluetoothManager()<CBCentralManagerDelegate,CBPeripheralDelegate,CBPeripheralManagerDelegate>
@property (nonatomic, strong) NSMutableArray *offlineperipherals;
@property (nonatomic, strong) NSMutableArray *tempLists;
@property (nonatomic, strong) CBPeripheral *peripheral;
@property (nonatomic, strong) CBPeripheralManager *peripheralmanager;
@implementation BlueInfo
@end

@implementation BluetoothManager

//單例生成
+(BluetoothManager *)share {
  static BluetoothManager *shareInstance_ = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      shareInstance_ = [[self alloc] init];
  });
  return shareInstance_;
}
 //初始化中心設(shè)備CBCentraManager(管理者)和CBPeripheralManager(外設(shè)管理者)
 -(id) init {
  self = [super init];
  if (self) {
    _cbCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    _peripheralmanager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
  }
  return self;
}
-(void) setDelegate:(id<BluetoothManagerDelegate>)delegate
{
  if (!_delegate) {
      _delegate = delegate;
  }
}

下面是中心設(shè)備的代理方法,步驟基本要按照下面的走:

1.檢查設(shè)備藍(lán)牙服務(wù)是否打開(可用),關(guān)于中心設(shè)備的狀態(tài)central.state有以下6個(gè)枚舉
- (void) centralManagerDidUpdateState:(CBCentralManager *)central{
  BOOL    state = false;
  NSString *msg = @"";
  switch (central.state) {
    case CBCentralManagerStatePoweredOn:{
        msg = @"Bluetooth is currently powered on";
        state = YES;
    }
    break;
    case CBCentralManagerStatePoweredOff:{
        msg = @"Bluetooth is currently powered off.";
    }
        break;
    case CBCentralManagerStateUnauthorized:{
        msg = @"The application is not authorized to use the Bluetooth Low Energy Central/Client role.";
    }
        break;
    case CBCentralManagerStateUnsupported:{
        msg = @"The platform doesn't support the Bluetooth Low Energy Central/Client role.";
    }
        break;
    case CBCentralManagerStateResetting:{
        msg = @"The connection with the system service was momentarily lost, update imminent.";
    }
        break;
    case CBCentralManagerStateUnknown:{
        msg = @"State unknown, update imminent.";
    }
        break;
  }
}
  NSLog(@"%@",msg);

只有在CBCentralManagerStatePoweredOn的狀態(tài)下,才可以進(jìn)行下步操作——其他狀態(tài),可以根據(jù)自身情況做相應(yīng)的提示高告訴用戶溉旋;

2.搜索中心設(shè)備周邊的外設(shè):

在上面代理方法的CBCentralManagerStatePoweredOncase下寫搜索方法,可以直接把系統(tǒng)方法寫到該case,此處把系統(tǒng)的搜索方法封裝到一個(gè)自定義方法,代碼更整潔(創(chuàng)建布爾值state,用于標(biāo)記設(shè)備藍(lán)牙成功與否)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
BOOL state = false;
NSString *msg = @"";
switch (central.state) {
case CBCentralManagerStatePoweredOn:{
msg = @"Bluetooth is currently powered on";
[self scanDevice];//搜索設(shè)備方法
state = YES;
}
break;
// ...... 下面的狀態(tài)省略......
}
}

下面是搜索設(shè)備封裝方法:

-(void) scanBlueServes {
  NSDictionary *optionsDict = @{CBCentralManagerScanOptionAllowDuplicatesKey:@YES};
  [self.cbCentralManager scanForPeripheralsWithServices:nil options:optionsDict];
//CBUUID *uuid = [CBUUID UUIDWithString:@"FFF0"];
//[self.cbCentralManager scanForPeripheralsWithServices:@[uuid] options:optionsDict];

}

方法中,需要注意的是:

  • 注釋的那部分代碼是用于指定搜索設(shè)備特定服務(wù)的uuid,nil則無差別搜索;
  • 如果想要改變默認(rèn)行為矛纹,可以指定CBCentralManagerScanOptionAllowDuplicatesKey作為掃描選項(xiàng)盖淡。此時(shí)愉粤,central管理器會(huì)在每次收到peripheral端的廣告包時(shí)都觸發(fā)一個(gè)事件遣蚀。在某些情況下關(guān)閉默認(rèn)行為很有用處孤紧,但記住指定CBCentralManagerScanOptionAllowDuplicatesKey掃描選項(xiàng)不利于電池的壽命及程序性能匣屡。因此潘飘,只在需要的時(shí)候使用這個(gè)選項(xiàng)以完成特定的任務(wù)。
    原文如下:
  • A Boolean value that specifies whether the scan should run without duplicate filtering.
    The value for this key is an NSNumber object. If true, filtering is disabled and a discovery event is generated each time the central receives an advertising packet from the peripheral. Disabling this filtering can have an adverse effect on battery life and should be used only if necessary. If false, multiple discoveries of the same peripheral are coalesced into a single discovery event. If the key is not specified, the default value is false.
3.檢測(cè)到外設(shè)后,進(jìn)入下面的代理方法,連接設(shè)備(這里開始加入了一些個(gè)人的方法)
  • 當(dāng)搜索到設(shè)備進(jìn)入這個(gè)代理方法:-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI,搜索到多個(gè)設(shè)備,則此方法多次調(diào)用;
    由于iOS端禁止獲取藍(lán)牙設(shè)備Mac地址,所以和硬件工程師協(xié)商好,將Mac地址放到指定廣播包里,從此方法中advertisementData以NSData傳過來,而這個(gè)key是蘋果指定的,不能亂寫;
    (余下的除了'central'分別是搜索到的設(shè)備:peripheral瘤袖,設(shè)備信號(hào):RSSI(數(shù)據(jù)類型參考方法)).
  • 我們可通過外設(shè)的名字 peripheral.name或者剛剛說的藍(lán)牙Mac地址來過濾設(shè)備,這就需要和硬件開發(fā)協(xié)商了,這里還做了一步處理,將已經(jīng)被其他設(shè)備連接的外設(shè)通過連接狀態(tài)的判斷也過濾掉
if (peripheral.state == CBPeripheralStateConnected) {
  return;
}
  • 過濾之后,將設(shè)備添加到self.findPeripherals數(shù)組中傳到界面(通過UITableView)展示出來:
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
    if (peripheral.state == CBPeripheralStateConnected) {
        return;
    }
  NSData *data = [advertisementData objectForKey:@"kCBAdvDataManufacturerData"];
  if ((peripheral.name && ([peripheral.name hasPrefix:@"BBCare"]) ||  [self checkMacAddress]){
    [self.findPeripherals addObject:peripheral];
}
4.通過界面方法,實(shí)現(xiàn)藍(lán)牙類方法;

一般情況下,我們(其實(shí)是我)會(huì)在tableView通過BluetoothManager單例獲取到findPeripherals數(shù)組,展示到界面,然后在tableview的協(xié)議方法:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
里面獲取要連接的設(shè)備peripheral,傳入如下方法實(shí)現(xiàn)連接設(shè)備:
[[BluetoothManager share].cbCentralManager connectPeripheral:peripheral options:nil];

5.連接后的處理(劃重點(diǎn)了!)
  • 連接失敗:
    有時(shí)候,藍(lán)牙搜索到設(shè)備時(shí)設(shè)備還在,點(diǎn)擊連接時(shí)設(shè)備不在附近或沒電(就不詳細(xì)說了),類似這些情況,連接會(huì)失敗,會(huì)進(jìn)入如下方法,NSLog一下,會(huì)打印出具體的失敗原因:
  -(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@">>>連接到名稱為(%@)的設(shè)備-失敗,原因:%@",[peripheral name],[error localizedDescription]);
}
  • 連接成功后,簽訂外設(shè)代理方法
    別以為連接成功了數(shù)據(jù)就會(huì)自己找你了,并不是,后面還有不少的坑呢.
    首先,連接成功后,會(huì)進(jìn)入另外一個(gè)代理方法",這里我把連接的設(shè)備添加進(jìn)self.connectperipherals數(shù)組以備不時(shí)之需,然后該設(shè)備需簽訂peripheral的代理,然后開始一起去了解外設(shè)的代理方法吧
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
  NSLog(@">>>連接到設(shè)備(%@ >> %@)-- 成功",peripheral.name,peripheral.identifier.UUIDString);
  if (self.connectperipherals == nil) {
      self.connectperipherals = [NSMutableArray array];
  }
  if (![self.connectperipherals containsObject:peripheral]) {
      [self.connectperipherals addObject:peripheral];
  }
  [peripheral setDelegate:self];
  [peripheral discoverServices:nil];
}
  • 發(fā)現(xiàn)外設(shè)服務(wù)CBService
    來到這里,就要打開硬件工程師寫給你的硬件對(duì)接的文檔,看看他們給你的設(shè)備里面有什么服務(wù)了
    外設(shè)一般都會(huì)有幾個(gè)服務(wù)衣摩,每個(gè)服務(wù)都會(huì)有幾個(gè)特征,服務(wù)和特征都是用不同的 UUID 來標(biāo)識(shí),每個(gè)特征的 properties 是不同的,就是說有不同的功能屬性后面會(huì)說到,不清楚的話,可以谷歌一下 "藍(lán)牙","服務(wù)","特征碼"等關(guān)鍵字;
    peripheral.services就是一個(gè)存有所有服務(wù)碼的數(shù)組,forin一下,看看里面有沒有你需要的?當(dāng)然,代碼里面的那個(gè)特征碼的UUID@"FFF1"是我亂寫的,大家可以根據(jù)自己的硬件去搜索特征碼,用到的方法是:
    [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:@"FFF1"]] forService:service];
//完整代碼
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
  NSLog(@">>>掃描到服務(wù):%@",peripheral.services);
  if (error){
      NSLog(@">>>發(fā)現(xiàn)服務(wù) %@ 錯(cuò)誤: %@", peripheral.name, [error localizedDescription]);
      return;
  }
  for (CBService *service in peripheral.services) {
      NSLog(@">>>掃描到服務(wù) = %@",service.UUID);
      [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:@"FFF1"]] forService:service];
  }
}
  • 發(fā)現(xiàn)外設(shè)服務(wù)中的特征碼CBCharacteristic
    剛也說到,和服務(wù)類似,特征碼也是以不同的 UUID 來標(biāo)識(shí),我們要對(duì)藍(lán)牙的操作,其實(shí)就是對(duì)這些特征碼搞事情了特征碼的屬性是一個(gè)枚舉類型:
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
};

在我的項(xiàng)目中用到的分別是:

CBCharacteristicPropertyWrite,                 //可寫入
CBCharacteristicPropertyWriteWithoutResponse,  //可寫入并帶回執(zhí)
CBCharacteristicPropertyRead,                  //可讀
CBCharacteristicPropertyNotify,                //可訂閱1
CBCharacteristicPropertyIndicate               //可訂閱2

會(huì)一點(diǎn)英文的同學(xué)看看類型后面大概能猜到,第一二個(gè)是寫入,一個(gè)帶回執(zhí),一個(gè)不帶;第三個(gè)是可讀;第四第五個(gè)是騷騷不同的兩種訂閱,具體根據(jù)不同的情況使用,其他的好像我也沒用到過...不過看后綴的話好像能發(fā)現(xiàn)些什么吧?

  • 發(fā)現(xiàn)外設(shè)的特征碼CBCharacteristic代理方法
    這也是通過forinservice.characteristics,判斷特征碼的UUID,對(duì)應(yīng)不同的特征碼做不同的操作,比如:
setNotifyValue forCharacteristic        //訂閱方法`;
writeValue: forCharacteristic: type:    //寫入方法,其中type類型有無回執(zhí)
peripheral readValueForCharacteristic:  //讀取方法

整段的代碼如下:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
  if (error) {
      NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
  }
  else{
      for (CBCharacteristic *characteristic in service.characteristics{
        NSLog(@"特征碼 == %@",characteristic.UUID);
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFF4"]]){
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFF3"]]){
            [peripheral writeValue:[NSData data] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
        }
     }
  }
}

不知不覺寫了這么多,還是分開上下部說吧...
iOS關(guān)于藍(lán)牙框架BLE的開發(fā)--基礎(chǔ)用法(下)

  • 操作特征碼后的回調(diào)——訂閱/讀取回調(diào)與失敗回調(diào)
  • 操作特征碼后的回調(diào)——寫入回調(diào)與失敗回調(diào))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艾扮,一起剝皮案震驚了整個(gè)濱河市既琴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泡嘴,老刑警劉巖甫恩,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異酌予,居然都是意外死亡磺箕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門抛虫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來松靡,“玉大人,你說我怎么就攤上這事建椰〉衿郏” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵棉姐,是天一觀的道長(zhǎng)屠列。 經(jīng)常有香客問我,道長(zhǎng)伞矩,這世上最難降的妖魔是什么笛洛? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮乃坤,結(jié)果婚禮上撞蜂,老公的妹妹穿的比我還像新娘。我一直安慰自己侥袜,他們只是感情好蝌诡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枫吧,像睡著了一般浦旱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上九杂,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天颁湖,我揣著相機(jī)與錄音,去河邊找鬼例隆。 笑死甥捺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镀层。 我是一名探鬼主播镰禾,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了吴侦?” 一聲冷哼從身側(cè)響起屋休,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎备韧,沒想到半個(gè)月后劫樟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡织堂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年叠艳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片易阳。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡附较,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闽烙,到底是詐尸還是另有隱情,我是刑警寧澤声搁,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布黑竞,位于F島的核電站,受9級(jí)特大地震影響疏旨,放射性物質(zhì)發(fā)生泄漏很魂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一檐涝、第九天 我趴在偏房一處隱蔽的房頂上張望遏匆。 院中可真熱鬧,春花似錦谁榜、人聲如沸幅聘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)帝蒿。三九已至,卻和暖如春巷怜,著一層夾襖步出監(jiān)牢的瞬間葛超,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工延塑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绣张,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓关带,卻偏偏與公主長(zhǎng)得像侥涵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 在寫這個(gè)博客之前独令,空余時(shí)間抽看了近一個(gè)月的文檔和Demo端朵,系統(tǒng)給的解釋很詳細(xì),接口也比較實(shí)用燃箭,唯獨(dú)有一點(diǎn)冲呢,對(duì)于設(shè)備...
    木易林1閱讀 3,345評(píng)論 3 4
  • 藍(lán)牙簡(jiǎn)介 藍(lán)牙( Bluetooth? ):是一種無線技術(shù)標(biāo)準(zhǔn),可實(shí)現(xiàn)固定設(shè)備招狸、移動(dòng)設(shè)備和樓宇個(gè)人域網(wǎng)之間的短距離...
    Chefil閱讀 2,030評(píng)論 2 19
  • 首先進(jìn)一則廣告: 藍(lán)牙技術(shù)聯(lián)盟(Bluetooth SIG)2010年7月7日宣布敬拓,正式采納藍(lán)牙4.0核心規(guī)范(B...
    L澤閱讀 1,427評(píng)論 3 4
  • 備注:下面說到的內(nèi)容都基于藍(lán)牙4.0標(biāo)準(zhǔn)以上,主要以實(shí)踐為主裙戏。 ~ CoreBluetooth.framework...
    未_漆小七閱讀 1,599評(píng)論 1 8
  • 星期一 星期二 星期三 一個(gè)禮拜總有那么幾天乘凸,太過情緒化了吧,今晚干了什么呢累榜?就是下課回來的路上一直在考慮要不要去...
    涂小鴉閱讀 230評(píng)論 0 0