在現(xiàn)在這份工作之前做了挺長(zhǎng)時(shí)間的“智能門禁”“智能家居”方面的Ios開發(fā)出牧,都是基于sip協(xié)議實(shí)現(xiàn)的手機(jī)與硬件設(shè)備的交互。用到的開源庫(kù)分別是idoubs(doubango)蛾扇、linphone攘烛,相比較而言linphone的通話效果會(huì)好些也更穩(wěn)當(dāng)一些。
在軟硬件結(jié)合的產(chǎn)品中藍(lán)牙開發(fā)是必不可少的屁桑,因?yàn)樗{(lán)牙是一種短距離医寿、高效、無需網(wǎng)絡(luò)的通訊方式蘑斧。Ios藍(lán)牙分為“中心者模式“和”外設(shè)模式“靖秩。前者是將手機(jī)作為藍(lán)牙信號(hào)的接收端,用來連接藍(lán)牙設(shè)備并實(shí)現(xiàn)手機(jī)與外設(shè)間的數(shù)據(jù)傳遞竖瘾。后者是將手機(jī)作為藍(lán)牙信號(hào)的發(fā)射端沟突,無需連接藍(lán)牙設(shè)備而只需通過發(fā)送廣播包的形式將數(shù)據(jù)(加密)廣播出去即可,外設(shè)中的藍(lán)牙模塊在接收到該數(shù)據(jù)后進(jìn)行解密->信息比對(duì)捕传,進(jìn)而進(jìn)行其他操作惠拭。
中心者模式?
這里需要使用到CoreBluetooth.framework中的CBCentralManager、CBPeripheral兩個(gè)類,分別用來連接藍(lán)牙和讀寫藍(lán)牙傳遞的數(shù)據(jù)职辅。
藍(lán)牙連接:
1棒呛、創(chuàng)建藍(lán)牙管理對(duì)象
CBCentralManager *manager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];
opetion: 設(shè)置系統(tǒng)自帶選項(xiàng)
CBCentralManagerOptionShowPowerAlertKey?? 默認(rèn)為NO即若手機(jī)藍(lán)牙未打開則不彈框提示,可設(shè)置為YES CBCentralManagerOptionRestoreIdentifierKey?? app被殺死域携,重新恢復(fù)manager的ID?CBCentralManagerScanOptionAllowDuplicatesKey ? 默認(rèn)為NO簇秒,過濾功能是否啟用,每次尋找都會(huì)合并相同的peripheral秀鞭。如果設(shè)為YES的話每次都能接受到來自peripherals的廣播包數(shù)據(jù)趋观。
CBCentralManagerScanOptionSolicitedServiceUUIDsKey ? 掃描的時(shí)候只會(huì)掃描到包含這些UUID的設(shè)備(數(shù)組)。CBConnectPeripheralOptionNotifyOnConnectionKey ? 默認(rèn)為NO锋边,APP被掛起時(shí)如果已連接到peripheral皱坛,是否要給APP一個(gè)提示框。
CBConnectPeripheralOptionNotifyOnDisconnectionKey 默認(rèn)為NO豆巨,APP被掛起時(shí)剩辟,恰好在這個(gè)時(shí)候斷開連接,要不要給APP一個(gè)斷開提示搀矫。
CBConnectPeripheralOptionNotifyOnNotificationKey 默認(rèn)為NO抹沪,APP被掛起時(shí),是否接受到所有的來自peripheral的包都要彈出提示框瓤球。
2、檢測(cè)手機(jī)藍(lán)牙狀態(tài)并掃描藍(lán)牙設(shè)備
#pragma mark CBCentralManagerDelegate
//上面創(chuàng)建中心管理者后 這里會(huì)自動(dòng)監(jiān)測(cè)藍(lán)牙的使用狀態(tài)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
根據(jù)central.state狀態(tài)值判斷:
CBCentralManagerStateUnknown未知狀態(tài)/CBCentralManagerStateResetting復(fù)位/CBCentralManagerStateUnsupported不支持/CBCentralManagerStateUnauthorized未授權(quán)/CBCentralManagerStatePoweredOff未開啟/CBCentralManagerStatePoweredOn已開啟
在藍(lán)牙開啟后執(zhí)行[manager scanForPeripheralsWithServices:nil options:nil];搜索全部藍(lán)牙 或?[manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"EEFF"]] options:nil];搜索指定UUID的藍(lán)牙敏弃。
3卦羡、連接藍(lán)牙設(shè)備
//發(fā)現(xiàn)外設(shè)
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{? //接下來在這里根據(jù)獲取的外設(shè)peripheral信息對(duì)搜索到的(符合特定服務(wù))藍(lán)牙做篩選。?
if([peripheral.name isEqualToString:@"TESTNAME"]) {
[self.centralManager connectPeripheral:peripheral options:nil];??? //連接
[self.centralManager stopScan];? }}???????? //停止掃描
4麦到、檢測(cè)與藍(lán)牙設(shè)備的連接狀態(tài)
//中心管理者連接外設(shè)成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
?//到這里上面中心管理者的代理方法就執(zhí)行完了绿饵,并且已經(jīng)連接到了指定的藍(lán)牙設(shè)備,所以下面要設(shè)置_peripheral的代理并開始讀取藍(lán)牙攜帶的數(shù)據(jù)瓶颠。
[peripheral setDelegate:self];
[peripheral discoverServices:nil]; //搜索該藍(lán)牙對(duì)應(yīng)的所有服務(wù)
}
//外設(shè)連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%s, line = %d, %@=連接失敗", __FUNCTION__, __LINE__, peripheral.name);
}
//丟失連接- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%s, line = %d, %@=斷開連接", __FUNCTION__, __LINE__, peripheral.name);
[self.centralManager connectPeripheral:peripheral options:nil]; ? ? ? ? ? ? ? //重新連接
}
讀寫藍(lán)牙數(shù)據(jù)
5拟赊、搜索藍(lán)牙特征
//已經(jīng)發(fā)現(xiàn)該藍(lán)牙對(duì)應(yīng)的服務(wù)(根據(jù)藍(lán)牙設(shè)備搜索服務(wù))
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error{
for(CBService *service in _peripheral.services) {
[_peripheral discoverCharacteristics:nil forService:service]; //搜索service服務(wù)對(duì)應(yīng)的特征
}}
6、根據(jù)特征屬性做對(duì)應(yīng)的讀寫操作
//已經(jīng)搜索到服務(wù)對(duì)應(yīng)的特征(根據(jù)服務(wù)搜索特征粹淋,然后判斷特征是否可讀吸祟、可寫,最后根據(jù)特征的讀寫屬性進(jìn)行寫入和讀取操作)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
for(CBCharacteristic *characteristic in service.characteristics) {
if((unsigned long)characteristic.properties == 10) { //支持讀寫的屬性對(duì)應(yīng)的特征才能寫入數(shù)據(jù)
[peripheral writeValue:[_inputStr dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse]; //將數(shù)據(jù)寫入指定的特征(即給藍(lán)牙設(shè)備發(fā)送數(shù)據(jù))
}}}
7桃移、檢測(cè)是否讀寫成功
//用于檢測(cè)中心向外設(shè)寫數(shù)據(jù)是否成功
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
NSLog(@"寫入藍(lán)牙特征數(shù)據(jù)失敗 = %@",error.userInfo); }
else{
NSLog(@"寫入藍(lán)牙特征數(shù)據(jù)成功"); }?
[peripheral readValueForCharacteristic:characteristic];}
8屋匕、訂閱特征并實(shí)時(shí)更新數(shù)據(jù)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
外設(shè)模式
這里需要用到CoreBluetooth.framework中的CBPeripheralManager類,把手機(jī)作為藍(lán)牙廣播包的發(fā)送者借杰。
1过吻、創(chuàng)建設(shè)備類對(duì)象并檢測(cè)手機(jī)藍(lán)牙狀態(tài)
CBPeripheralManager *manager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];
#pragma mark CBPeripheralMangerDelegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
2、發(fā)廣播包
[manager startAdvertising:@{CBAdvertisementDataLocalNameKey : @"將顯示的藍(lán)牙名稱", CBAdvertisementDataServiceUUIDsKey:@"自定義的UUID"}];
注:startAdvertising這個(gè)方法只允許設(shè)置CBAdvertisementDataLocalNameKey(本地名稱)蔗衡、CBAdvertisementDataServiceUUIDsKey(UUID)兩個(gè)參數(shù)纤虽,其他鍵值key可在“中心模式”下的設(shè)備中查看使用乳绕。 CBAdvertisementDataIsConnectable(外設(shè)的可連接數(shù))這個(gè)參數(shù)是廣播包自帶的默認(rèn)參數(shù)(1->可連接 0->不可連接)。廣播包中能傳輸?shù)臄?shù)據(jù)最多為32個(gè)字節(jié)逼纸。
3刷袍、檢測(cè)手機(jī)廣播是否成功
//手機(jī)已經(jīng)開始廣播廣播
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(nullable NSError *)error;
下面簡(jiǎn)要說明下我們產(chǎn)品的藍(lán)牙應(yīng)用場(chǎng)景
“中心者模式”:
步驟:開啟藍(lán)牙->搜索固定標(biāo)示的藍(lán)牙設(shè)備->連接藍(lán)牙->向藍(lán)牙模塊寫入加密指令->藍(lán)牙模塊將指令信息輸出到硬件主板->執(zhí)行具體操作
注:為了用戶有更好的使用體驗(yàn),這里的連接藍(lán)牙是自動(dòng)連接即連接時(shí)無需授權(quán)(藍(lán)牙模塊開發(fā)人員處理)樊展,且為了保證藍(lán)牙連接的穩(wěn)定性我們使用的藍(lán)牙最大連接數(shù)為一個(gè)呻纹。
“外設(shè)模式”:
步驟:開啟藍(lán)牙->將帶有固定標(biāo)示的加密數(shù)據(jù)寫入廣播包的CBAdvertisementDataLocalNameKey中->硬件中的藍(lán)牙模塊識(shí)別到該數(shù)據(jù)包并將相關(guān)數(shù)據(jù)輸出到主板->解密數(shù)據(jù)并執(zhí)行相應(yīng)操作
注:這個(gè)方式需要和藍(lán)牙模塊開發(fā)人員、硬件開發(fā)人員共同制定數(shù)據(jù)傳輸協(xié)議