本文主要介紹基于藍牙4.0的智能硬件開發。藍牙4.0主要基于<CoreBluetooth/CoreBluetooth.h>這個庫文件,下面將以此介紹每個類的作用.并提供自己對這些類封裝,最后附有代碼的連接。
CBCentralManager:負責查詢用戶藍牙的狀態、掃描周圍可見的外設、停止掃描、連接指定的外設等方法通過該類提供,并且通過代理的形式回調當前藍牙的狀態;
-(void)centralManagerDidUpdateState:(CBCentralManager *)central {
}
掃描到的外設;
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
}
連接指定外設
[centralManager connectPeripheral:peripheral options:nil];
以及連接外設的狀態。
//斷開連接
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
}
//連接失敗
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
}
//連接成功
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
}
CBCentralManager的掃描和連接通過其.h文件我們都能一目了然看出,說一下查詢用戶狀態這方法,這個方法的觸發時機其實在初始化CBCentralManager的時候,系統內部會進行相應Api的調用,我們只要在對應的回調中監聽即可。
[[CBCentralManager alloc] initWithDelegate:self queue:nil];
對于queue這個參數我在最后會做一些介紹,一般只需要給nil代表所有回調會在主線程中。
對于作過藍牙相關開發的,有可能會對這一系列類進行一些封裝,夠后面使用,而對于CBCentralManager以懶加載的形式提供,這樣容易造成一個問題--->用戶藍牙狀態的查詢加只會進行一次查詢,在切換另一個業務頁面的時候無法獲取當前用戶藍牙狀態,造成用戶體驗不佳。下面介紹CBPeripheral
CBPeripheral:一種對外設的抽象,一個CBPeripheral對應一個外設,它最重要的兩個特性是外設的服務地址和特性地址,通過服務地址我們可以找到特性地址,找到特性地址我們就可以寫數據了。下面來介紹具體流程。
在何時查找服務,當然是在連接外設成功的時候了
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
self.currentperipheral = peripheral;//保存起來,后面用的到
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
}
從方法字面意思我們也可以看出大概delegate用來回調服務地址的查找情況,其中的services:是一個外設服務地的數組,可以傳nil,則會查找外設的所有服務地址。
//發現的服務地址
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
}
到了這一步我們就可以比照相應硬件的協議文檔了,如果協議文檔中的服務地址被發現了,可以繼續下一步了-->該服務地址下的特性地址。
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
if ([service.UUID isEqual:[CBUUID UUIDWithString:addresString]]) {//協議文檔提供的服務地址
[peripheral discoverCharacteristics:nil forService:service];
} else continue;
}
}
//對應服務地址下的特性值,特性值一般包含讀和寫,讀用來接收外設的信息,寫:向外設寫數據。
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:charactDict[BlueCharacteristicRead]]]) {
#ifdef DEBUG
//NSLog(@"the charact read address:%@",charactDict[BlueCharacteristicRead]);
#endif
[peripheral setNotifyValue:YES forCharacteristic:characteristic];//接收外設的數據
}
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:charactDict[BlueCharacteristicWrite]]]) {
#ifdef DEBUG
// NSLog(@"the charact write address:%@",charactDict[BlueCharacteristicWrite]);
#endif
self.characteristic = characteristic;//把寫的特征值保存起來,用來向外設寫值、
}
}
}
到這里我們就可以向外設寫值和接收數據了
寫:
[self.currentperipheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
通過回調可知道寫入是否失敗(一般不需要處理)
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error {
}
外設發送的數據是通過下面方法來接收
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
}
iOS藍牙開發的大致流程介紹到此了,前面說過centralManager初始化之后還有個queue參數,該參數可以的作用就是把上面涉及到的一些回調都加入到該隊列中,加入到該隊列中好處就是可以控制代碼的執行順序,我們只要把鏈接,掃描等操作也加入到該隊列,就達到順序的控制,不過這個沒很大必要。
下面我給一個我自己封裝的一個藍牙庫。提供了Mac地址的讀取,和搜索同一類型的外設,斷開重新連接,使用起來不難。
[YYBlueManger sharedManger].delegate = self;
[[YYBlueManger sharedManger] scan];
#pragma mark - YYBlueMangerDelegate
-(void)blueManagerFailedState:(YYBlueManger *)manager statu:(YYBlueManagerState)statu{
//用戶藍牙狀態不正常時候調用。
}
-(void)blueManagerblescanBluDevice:(YYBlueManger *)manager andTheDevice:(CBPeripheral *)peripheral {
//NSLog(@"%@",peripheral.name);
if ([peripheral.name isEqualToString:@"你想連接的外設名字"]) {
if ([YYBlueManger sharedManger].connectState == YYBlueConnectStateConnected || [YYBlueManger sharedManger].connectState ==YYBlueConnectStateConnecting) {
return;
}
[[YYBlueManger sharedManger] connect:peripheral orTheDeviceName:nil];
}
}
-(NSArray *)blueManagerServerAdrres:(YYBlueManger *)manager peripheral:(CBPeripheral *)peripheral {
return @[@"0xxxx"];
}
-(NSDictionary *)blueManagerCharacteristicsAdrres:(YYBlueManger *)manager peripheral:(CBPeripheral *)peripheral {
return @{BlueCharacteristicWrite:@"0xxxxx",BlueCharacteristicRead:@"0xxxxx"};
}
-(void)blueManagerdidConnectSuccees:(YYBlueManger *)manager peripheral:(CBPeripheral *)peripheral {
NSLog(@"連接成功");
[[YYBlueManger sharedManger] stop];
}
-(void)blueManagerFailedConnect:(YYBlueManger *)manager peripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"連接失敗");
[[YYBlueManger sharedManger] scan];
}
-(void)blueManagerCutConnect:(YYBlueManger *)manager peripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"斷開連接");
[[YYBlueManger sharedManger] scan];
}
[[YYBlueManger sharedManger] writeDataToDevice:nil writeHandle:nil];
github連接:https://github.com/jsonsnow/CoreBlue.git
好久沒接觸智能硬件了,這幾天又開始智能硬件的開發,用自己寫的庫也發現其中存在幾個問題
在resetConnect的時候,發現維持的connect狀態混亂,因為在取消前一個已經連接的外設的時候會調用disConnect方法,導致connectSate = connectSateCut,此事發現同名字設備的時候,因為connectSate == connectSateCut,因此會進行連接,解決方法:增加一個cancelSate ,在disConnect中如果connectSate = cancelSate,則直接返回
增加一個打斷協議,在將要連接外設的時候調用willConntetn方法,如果實現方返回YES,則不進行此次連接,主要針對多設備綁定而設計
取消Mac地址讀取,以及不把已經連接的設備加入數據源中
增加一個搜索外設的方法,可以給定 @"xxx1,xxx2",則會搜索名字為xxx1和xxx2的外設,這個場景主要是針對外設名字不同但是其服務地址和特許值都相同的情形
目前最新的版本還沒上傳,如有需要可以留下郵箱