如果你進(jìn)來(lái)了,點(diǎn)下關(guān)注行不行_
隨說(shuō) : 網(wǎng)上資料一大堆, 可以隨便google搜一下加深理解, 這里作一個(gè)整理, 可收藏起來(lái)當(dāng)資料隨時(shí)翻查
藍(lán)牙常用框架 : CoreBluetooth
藍(lán)牙常用庫(kù) :
BabyBluetooth
YmsCoreBluetooth
基本概念要搞清楚
1. 名詞解釋#
CoreBluetooth框架的核心其實(shí)是兩個(gè)東西,peripheral(CBCebtralManager類)和central(CBPeripheralManager類), 可以理解成外設(shè)和中心
打個(gè)比喻.小米手環(huán)是peripheral,我們的iphone手機(jī)是central,所以就會(huì)大量使用CBCebtralManager類。(Iphone理解為連接)
又比如像用一個(gè)ipad和一個(gè)iphone通訊, ipad可以認(rèn)為是central玄糟,iphone端是peripheral ,這種情況下在iphone端就要使用CBPeripheralManager類來(lái)開發(fā)了烈炭。(Iphone理解為外設(shè))
發(fā)起連接的時(shí)central,被連接的設(shè)備為perilheral
每個(gè)藍(lán)牙4.0的設(shè)備都是通過(guò)服務(wù)和特征來(lái)展示自己的
service : 一個(gè)設(shè)備必然包含一個(gè)服務(wù)以上(至少包含一個(gè)服務(wù),有可能包含更多的服務(wù))
characteristic : 包含在服務(wù)下, 描述該服務(wù)下特定的功能的, 一般擁有多個(gè)characteristic, 而且characteristic有類型, 讀(read), 寫(write), 通知(notify)等
UUID(Universally Unique Identifier) : 設(shè)備的每一個(gè)service有他相應(yīng)的UUID, 同時(shí)每一個(gè)characteristic也有相應(yīng)的UUID
簡(jiǎn)單理解 : service and characteristic 每個(gè)設(shè)備會(huì)提供服務(wù)和特征流礁,類似于服務(wù)端的api,但是機(jī)構(gòu)不同。每個(gè)外設(shè)會(huì)有很多服務(wù)晶伦,每個(gè)服務(wù)中包含很多字段,這些字段的權(quán)限一般分為 讀read啄枕,寫write婚陪,通知notiy幾種,就是我們連接設(shè)備后具體需要操作的內(nèi)容频祝。
注 : 藍(lán)牙設(shè)備硬件廠商通常都會(huì)提供他們的設(shè)備里面各個(gè)服務(wù)(service)和特征(characteristics)的功能泌参,比如哪些是用來(lái)交互(讀寫),哪些可獲取模塊信息(只讀)等, 也就是說(shuō), 藍(lán)牙設(shè)備硬件廠商, 提供了這些
2. 開發(fā)基本步驟#
- 建立中心角色
- 掃描外設(shè)(discover)
- 連接外設(shè) (connect)
- 掃描外設(shè)中的服務(wù)和特征(discover)
- 4.1 獲取外設(shè)的services
- 4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值常空,獲取Characteristics的Descriptor和Descriptor的值
- 與外設(shè)做數(shù)據(jù)交互(explore and interact)
- 訂閱Characteristic的通知
- 斷開連接(disconnect)
一 : 建立中心角色####
// 連接中心角色, 所謂的中心角色,就是藍(lán)牙設(shè)備管理對(duì)象, 可以把他理解為主設(shè)備沽一,通過(guò)他,可以去掃描和鏈接外設(shè)
// 初始化并設(shè)置委托和線程隊(duì)列漓糙,最好一個(gè)線程的參數(shù)可以為nil铣缠,默認(rèn)會(huì)就main線程
self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
// 這個(gè)是BabyBluetooth第三方庫(kù)
// 單例模式
+ (instancetype)shareBabyBluetooth {
static BabyBluetooth *share = nil;
static dispatch_once_t oneToken;
dispatch_once(&oneToken, ^{
share = [[BabyBluetooth alloc]init];
});
return share;
}
- (instancetype)init {
self = [super init];
if (self) {
//初始化對(duì)象
babyCentralManager = [[BabyCentralManager alloc]init];// 藍(lán)牙中心模式實(shí)現(xiàn)類
babySpeaker = [[BabySpeaker alloc]init]; // block查找和channel切換
babyPeripheralManager = [[BabyPeripheralManager alloc]init]; // 外設(shè)模式實(shí)現(xiàn)類
// babyPeripheralManager里面有一個(gè)成員屬性babySpeaker , 將這個(gè)賦值于它
babyPeripheralManager->babySpeaker = babySpeaker;
// babyCentralManager里面有一個(gè)成員屬性babySpeaker , 將這個(gè)賦值于它
babyCentralManager->babySpeaker = babySpeaker;
}
return self;
}
// 注冊(cè)藍(lán)牙中心后, 必須調(diào)用的代理方法, 不然會(huì)報(bào)錯(cuò)
// 主設(shè)備狀態(tài)改變的委托,在初始化CBCentralManager的適合會(huì)打開設(shè)備,只有當(dāng)設(shè)備正確打開后才能使用
// 特別注意, 需要在狀態(tài)CBCentralManagerStatePoweredOn下才能使用任何設(shè)備
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
//發(fā)送通知
[[NSNotificationCenter defaultCenter]postNotificationName:BabyNotificationAtCentralManagerDidUpdateState object:@{@"central":central}];
switch (central.state) {
case CBCentralManagerStateUnknown:
BabyLog(@">>>CBCentralManagerStateUnknown");
break;
case CBCentralManagerStateResetting:
BabyLog(@">>>CBCentralManagerStateResetting");
break;
case CBCentralManagerStateUnsupported:
BabyLog(@">>>CBCentralManagerStateUnsupported");
break;
case CBCentralManagerStateUnauthorized:
BabyLog(@">>>CBCentralManagerStateUnauthorized");
break;
case CBCentralManagerStatePoweredOff:
BabyLog(@">>>CBCentralManagerStatePoweredOff");
break;
case CBCentralManagerStatePoweredOn:
BabyLog(@">>>CBCentralManagerStatePoweredOn");
[[NSNotificationCenter defaultCenter] postNotificationName:BabyNotificationAtCentralManagerEnable object:@{@"central":central}];
break;
default:
break;
}
//狀態(tài)改變callback
if ([currChannel blockOnCentralManagerDidUpdateState]) {
[currChannel blockOnCentralManagerDidUpdateState](central);
}
}
二 : 掃描設(shè)備####
// 框架提供的方法
/*!
* @method scanForPeripheralsWithServices:options:
*
* @param serviceUUIDs UUID列表, 參數(shù)有值的話則只掃描改UUID
* @param options An optional dictionary specifying options for the scan.
*
*
* @see 發(fā)現(xiàn)設(shè)備就會(huì)調(diào)用這個(gè)代理方法 centralManager:didDiscoverPeripheral:advertisementData:RSSI:
* @seealso CBCentralManagerScanOptionAllowDuplicatesKey
* @seealso CBCentralManagerScanOptionSolicitedServiceUUIDsKey
*
*/
- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options;
// 當(dāng)然有掃描方法就有停止掃描的方法
/*!
* @method stopScan:
*
* @discussion Stops scanning for peripherals.
*
*/
- (void)stopScan;
//這個(gè)是BabyBluetooth第三方庫(kù)實(shí)現(xiàn)的掃描方法
//掃描Peripherals
- (void)scanPeripherals {
[centralManager scanForPeripheralsWithServices:[currChannel babyOptions].scanForPeripheralsWithServices options:[currChannel babyOptions].scanForPeripheralsWithOptions];
}
三 : 發(fā)現(xiàn)設(shè)備 - 連接設(shè)備####
//這個(gè)是BabyBluetooth第三方庫(kù)實(shí)現(xiàn)的連接方法
//掃描到Peripherals, 當(dāng)掃描到設(shè)備, 就會(huì)執(zhí)行這個(gè)代理方法entralManager:didDiscoverPeripheral:advertisementData:RSSI:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
//日志
//BabyLog(@"當(dāng)掃描到設(shè)備:%@",peripheral.name);
[self addDiscoverPeripheral:peripheral];
//發(fā)出通知
[[NSNotificationCenter defaultCenter]postNotificationName:BabyNotificationAtDidDiscoverPeripheral
object:@{@"central":central,@"peripheral":peripheral,@"advertisementData":advertisementData,@"RSSI":RSSI}];
//掃描到設(shè)備callback
if ([currChannel filterOnDiscoverPeripherals]) {
if ([currChannel filterOnDiscoverPeripherals](peripheral.name,advertisementData,RSSI)) {
// 執(zhí)行回調(diào)Block, 然后就會(huì)執(zhí)行setBlockOnDiscoverToPeripherals:(void (^)(CBCentralManager *central,CBPeripheral *peripheral,NSDictionary *advertisementData, NSNumber *RSSI))block
if ([currChannel blockOnDiscoverPeripherals]) {
[[babySpeaker callbackOnCurrChannel] blockOnDiscoverPeripherals](central,peripheral,advertisementData,RSSI);
}
}
}
//處理連接設(shè)備
if (needConnectPeripheral) {
if ([currChannel filterOnconnectToPeripherals](peripheral.name,advertisementData,RSSI)) {
[centralManager connectPeripheral:peripheral options:[currChannel babyOptions].connectPeripheralWithOptions];
//開一個(gè)定時(shí)器監(jiān)控連接超時(shí)的情況
connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(disconnect:) userInfo:peripheral repeats:NO];
}
}
}
注意 :
1, 回調(diào)這個(gè)代理方法,(CBPeripheral *)peripheral就是返現(xiàn)到的服務(wù), 必須保存下來(lái)作為
2, 需要過(guò)濾搜索結(jié)果, 可以通過(guò)filterOnDiscoverPeripherals Block
------------
連接成功與失敗,斷開連接等會(huì)調(diào)用的三個(gè)代理方法
//連接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
NSLog(@">>>連接到名稱為(%@)的設(shè)備-成功",peripheral.name);
}
//連接到Peripherals-失敗
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@">>>連接到名稱為(%@)的設(shè)備-失敗,原因:%@",[peripheral name],[error localizedDescription]);
}
//Peripherals斷開連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@">>>外設(shè)連接斷開連接 %@: %@\n", [peripheral name], [error localizedDescription]);
}
---------------
//BabyBluetooth第三方庫(kù)實(shí)現(xiàn)的連接情況Block
//設(shè)置設(shè)備連接成功的委托,同一個(gè)baby對(duì)象攘残,使用不同的channel切換委托回調(diào)
[baby setBlockOnConnectedAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral) {
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"設(shè)備:%@--連接成功",peripheral.name]];
}];
//設(shè)置設(shè)備連接失敗的委托
[baby setBlockOnFailToConnectAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
NSLog(@"設(shè)備:%@--連接失敗",peripheral.name);
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"設(shè)備:%@--連接失敗",peripheral.name]];
}];
//設(shè)置設(shè)備斷開連接的委托
[baby setBlockOnDisconnectAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
NSLog(@"設(shè)備:%@--斷開連接",peripheral.name);
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"設(shè)備:%@--斷開失敗",peripheral.name]];
}];
一些坑爹的情況#
1.為什么掃描不到外設(shè)拙友?
->情況1:設(shè)備不支持
babybluetooth支持BLE4.0藍(lán)牙設(shè)備,如果是2.0的設(shè)備歼郭,那肯定掃描不到
模擬器不支持藍(lán)牙調(diào)試遗契,必須使用真機(jī)調(diào)試
ios操作系統(tǒng)至少要在6.0以上
->情況2:外設(shè)沒(méi)有開啟廣播
默認(rèn)情況下打開手機(jī)或者ipad的藍(lán)牙,在使用babybluetooth是掃描不到設(shè)備的病曾,因?yàn)槭謾C(jī)和ipad只是打開了藍(lán)牙設(shè)備的電源而已牍蜂,并沒(méi)有發(fā)送廣播,如果想掃描到設(shè)備泰涂,需要編程的方式鲫竞,通過(guò)iphone或ipad,mac發(fā)送藍(lán)牙廣播逼蒙。demo程序中有一個(gè)iphone和一個(gè)mac發(fā)送藍(lán)牙廣播的程序从绘。
已連接的設(shè)備會(huì)停止廣播,所以也搜索不到
->情況3:為什么系統(tǒng)的藍(lán)牙能找到設(shè)備是牢,但是使用babybluetooth的demo卻無(wú)法找到僵井?
這種情況一般是因?yàn)槟莻€(gè)藍(lán)牙設(shè)備是支持MFI的,并不是普通的ble設(shè)備驳棱。
關(guān)于MFI這里補(bǔ)充一下 :
MFI ( make for ipad ,iphone, itouch ), 專們?yōu)樘O果設(shè)備制作的設(shè)備, 開發(fā)使用的是 ExternalAccessory 框架
所以這篇文章不予談?wù)?/p>