從上家公司離職已經(jīng)快半年了,與藍(lán)牙打了一年的交道,從小白一個(gè)到略知一二。最近在整理上一家公司做的一些項(xiàng)目,突發(fā)奇想,自己封裝一個(gè)藍(lán)牙庫(kù),方便以后的使用。說(shuō)干就干,如果需要項(xiàng)目代碼,猛擊這里GJLightBlueTooth。如果有用,請(qǐng)賞顆小星星。
GJLightBlueTooth架構(gòu)
當(dāng)初為了不在一個(gè)類里面同時(shí)處理發(fā)送與接收邏輯,也本著對(duì)外封閉的原則,為了給使用庫(kù)的人一個(gè)簡(jiǎn)單的類,就設(shè)計(jì)了:
用戶 ——> GJLightBlueTooth ——> CoreBlueTooth ——> GJLightBlueTooth ——> 用戶
這樣的架構(gòu)
其中:
- GJLightBlueTooth:相當(dāng)于一個(gè)中介,架起來(lái)自頁(yè)面用戶的指令和系統(tǒng)CoreBlueTooth交互的橋梁,這里的交互包括向藍(lán)牙設(shè)備發(fā)送指令和設(shè)置回調(diào)。
- GJLBTCentralManager:所有與系統(tǒng)CoreBlueTooth的溝通都在這里進(jìn)行,這里將指令發(fā)出去,也在這里獲取回調(diào),通過(guò)block回傳。
另外,在Demo中,你還會(huì)看到MyBLETool這個(gè)類,這是為了將Demo項(xiàng)目中頁(yè)面與業(yè)務(wù)分離而單獨(dú)出來(lái)的一個(gè)類,可以理解為設(shè)備類。為了我們不需要在具體的頁(yè)面中去設(shè)置回傳的block。
使用
在創(chuàng)建頁(yè)面后,你應(yīng)該初始化GJLightBlueTooth藍(lán)牙工具:self.BLE = [[GJLightBlueTooth alloc] init]。
在獲取到Characteristic后,你應(yīng)該根據(jù)實(shí)際讀寫的Characteristic匹配出設(shè)備上的CBCharacteristic,保存在本地,用于后面的寫與讀。
[self.BLE setBlockWhenDiscoverCharacteristics:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
strongify(self);
for (CBCharacteristic *cha in service.characteristics){
if ([cha.UUID.UUIDString isEqualToString:CharacteristicUUIDWrite]){
self.writeCharacter = cha;
}
}
//[[NSNotificationCenter defaultCenter] postNotificationName:@"DiscoverCharacteristics" object:service];
}];
掃描
[self.BLE scan]
停止掃描
[self.BLE stopScan]
連接設(shè)備
[self.BLE connectWithPeripheral:peri]
斷開(kāi)連接
[self.BLE cancelConnectWithPeripheral:peri]
讀取信號(hào)量
[self.BLE readRSSIWithPeriperal:peri]
發(fā)送數(shù)據(jù)
[self.BLE sendDataToPeriperal:peri WriteCharacteristic:self.writeCharacter Command:command NSEncoding:encoding]
這里針對(duì)現(xiàn)在很多公司提出需要手機(jī)與設(shè)備有心跳的要求,開(kāi)啟了一個(gè)線程隊(duì)列。該隊(duì)列設(shè)置能夠同時(shí)存在的指令數(shù)為3。
NSData *cmdData = [[NSString stringWithFormat:@"%@",command] dataUsingEncoding:encoding];
NSOperation *opration = [NSBlockOperation blockOperationWithBlock:^{
[peripheral writeValue:cmdData
forCharacteristic:writeCharacteristics
type:CBCharacteristicWriteWithoutResponse];
/*
* you can set thread time interval.but the order while delay when there are a lot of orders.
*/
//[NSThread sleepForTimeInterval:SleepTimeGap];
}];
[self.writeQueue addOperation:opration];
你也可以設(shè)置指令間隔時(shí)間,但是這樣會(huì)造成因心跳刷新過(guò)快造成的延遲發(fā)送。
注意
- 在新版本的iOS中,已經(jīng)不允許通過(guò)
peripheral.RSSI來(lái)獲取設(shè)備的信號(hào)量,必須在用[peripheral readRSSI]后,使用回調(diào)來(lái)獲取。這就會(huì)造成在掃描到設(shè)備時(shí)候無(wú)法顯示信號(hào)量。所以專門創(chuàng)建了一個(gè)分類CBPeripheral+RSSI,利用Runtime來(lái)動(dòng)態(tài)給peripheral創(chuàng)建了一個(gè)rssi屬性。
char nameKey;
- (void)setRssi:(NSNumber *)rssi{
objc_setAssociatedObject(self, &nameKey, rssi, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSNumber *)rssi{
return objc_getAssociatedObject(self, &nameKey);
}
- 在MyBLETool中,需要設(shè)置GJLBTCentralManager回調(diào)流,這里為了防止循環(huán)引用,需要進(jìn)行weak-strong dance。
weakify(self);
[self.BLE setBlockWhenDiscoverCharacteristics:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
strongify(self);
for (CBCharacteristic *cha in service.characteristics){
if ([cha.UUID.UUIDString isEqualToString:CharacteristicUUIDWrite]){
self.writeCharacter = cha;
}
}
//[[NSNotificationCenter defaultCenter] postNotificationName:@"DiscoverCharacteristics" object:service];
}];
最后是兩張demo的效果
如果需要項(xiàng)目代碼,猛擊這里GJLightBlueTooth。如果有用,請(qǐng)賞顆小星星。