iOS藍(lán)牙框架

1、概念介紹

本文所說的藍(lán)牙開發(fā)是基于蘋果<CoreBluetooth/CoreBluetooth.h>框架的藍(lán)牙功能開發(fā)。
基本概念:
中心設(shè)備:用于掃描周邊藍(lán)牙外設(shè)的設(shè)備,在iOS開發(fā)中,手機(jī)就是我們的中心設(shè)備。
外部設(shè)備:被掃描的藍(lán)牙設(shè)備,比如電子手表、藍(lán)牙耳機(jī)或其他藍(lán)牙設(shè)備。
廣播:外部設(shè)備不斷發(fā)送藍(lán)牙藍(lán)牙信號(hào),供中心設(shè)備掃描到。
服務(wù)(CBService):設(shè)備之間進(jìn)行數(shù)據(jù)交換的基礎(chǔ)單位,設(shè)備連接后可以進(jìn)行,讀取服務(wù)和寫入服務(wù)、更新服務(wù)。
特征(CBCharacteristic):服務(wù)下的子單位,數(shù)據(jù)在服務(wù)上的具體載體。一個(gè)服務(wù)會(huì)有多個(gè)特征,每個(gè)特征會(huì)有value來承載數(shù)據(jù)。
UUID:區(qū)分不同服務(wù)和特征的唯一標(biāo)識(shí)符。
當(dāng)我們進(jìn)行藍(lán)牙開發(fā)時(shí),一般是在iPhone上,以中心設(shè)備的模式進(jìn)行開發(fā)。步驟為:
1、檢測藍(lán)牙狀態(tài)
2、掃描周邊設(shè)備藍(lán)牙
3、連接藍(lán)牙
4、讀取服務(wù)及特征數(shù)據(jù),進(jìn)行數(shù)據(jù)交互
外設(shè)設(shè)備開發(fā):
1、檢測藍(lán)牙狀態(tài)
2、創(chuàng)建藍(lán)牙對(duì)象設(shè)置代理,等待被連接
3、寫入特征和讀取特征,與中心設(shè)備進(jìn)行數(shù)據(jù)交互
我們可以使用蘋果電腦作為外設(shè),蘋果手機(jī)作為中心設(shè)備,模擬兩個(gè)設(shè)備的藍(lán)牙交互流程。
為了更好的理解藍(lán)牙功能開發(fā),我們確定一個(gè)練習(xí)的目標(biāo):在蘋果電腦上使用藍(lán)牙傳輸一張圖片數(shù)據(jù)到手機(jī)上,然后在手機(jī)上進(jìn)行顯示。
由于圖片比較大,在傳輸過程中我們需要對(duì)數(shù)據(jù)進(jìn)行分割傳輸。

2、模擬外部設(shè)備開發(fā)

1、首先創(chuàng)建工程,導(dǎo)入框架

#import <CoreBluetooth/CoreBluetooth.h>

2、創(chuàng)建外設(shè)CBPeripheralManager對(duì)象

@property(nonatomic,strong)CBPeripheralManager* peripheralManager;
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];

設(shè)置ViewController為代理,設(shè)置回調(diào)隊(duì)列為主隊(duì)列。
3、實(shí)現(xiàn)代理方法
當(dāng)檢測到藍(lán)牙狀態(tài)發(fā)生改變時(shí),系統(tǒng)會(huì)調(diào)用狀態(tài)改變的代理方法,通知我們藍(lán)牙是否可用。

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    switch (peripheral.state) {
        case CBPeripheralManagerStatePoweredOff:
            NSLog(@"藍(lán)牙關(guān)閉");
            break;
        case CBPeripheralManagerStatePoweredOn:
            NSLog(@"藍(lán)牙打開");
            //廣播數(shù)據(jù)
            [self startAdvertising];
            break;
        default:
            NSLog(@"藍(lán)牙狀態(tài)不明");
            break;
    }
}

我們?cè)谒{(lán)牙打開的回調(diào)里面添加廣播的數(shù)據(jù),告訴中心設(shè)備,我們的特征。

- (void)startAdvertising {
    CBUUID* peripheralServiceUUID = [CBUUID UUIDWithString:@"AD01"];
    NSDictionary *para = @{
        CBAdvertisementDataLocalNameKey : @"macblue",
        CBAdvertisementDataServiceUUIDsKey : @[peripheralServiceUUID],
    };
//    開始廣播
    [self.peripheralManager startAdvertising:para];
}

startAdvertising方法中的字典只能添加兩個(gè)key,分別為CBAdvertisementDataLocalNameKey,CBAdvertisementDataServiceUUIDsKey。我們最多可用傳遞28個(gè)字節(jié)數(shù)據(jù)。
當(dāng)中心設(shè)備掃描時(shí),會(huì)掃描到我們?cè)O(shè)置的廣播數(shù)據(jù)。
如下:

{
    kCBAdvDataIsConnectable = 1;
    kCBAdvDataLocalName = macblue;
    kCBAdvDataRxPrimaryPHY = 0;
    kCBAdvDataRxSecondaryPHY = 0;
    kCBAdvDataServiceUUIDs =     (
        AD01
    );
    kCBAdvDataTimestamp = "727518148.203617";
    kCBAdvDataTxPowerLevel = 12;
}

中心設(shè)備以kCBAdvDataLocalName = macblue和kCBAdvDataServiceUUIDs = (AD01)來判斷設(shè)備是否為我們需要連接的測試設(shè)備。
此時(shí),我們的外部設(shè)備以及準(zhǔn)備好,等待中心設(shè)備掃描連接。

3、中心設(shè)備開發(fā)

導(dǎo)入藍(lán)牙框架

#import <CoreBluetooth/CoreBluetooth.h>

創(chuàng)建藍(lán)牙對(duì)象

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];

實(shí)現(xiàn)代理方法

//藍(lán)牙狀態(tài)發(fā)生改變調(diào)用的代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;

各種狀態(tài)如下,當(dāng)藍(lán)牙狀態(tài)為CBManagerStatePoweredOn時(shí)可對(duì)藍(lán)牙進(jìn)行操作。

typedef NS_ENUM(NSInteger, CBManagerState) {
    CBManagerStateUnknown = 0,
    CBManagerStateResetting,
    CBManagerStateUnsupported,
    CBManagerStateUnauthorized,
    CBManagerStatePoweredOff,
    CBManagerStatePoweredOn,
} NS_ENUM_AVAILABLE(10_13, 10_0);

開始掃描周圍藍(lán)牙設(shè)備

- (void)scanDeviceWithServicerUUID:(NSString *)servicerUUID {
    NSLog(@"開始掃描服務(wù):%@",servicerUUID);
    if (servicerUUID) {
        CBUUID* servicesUUID = [CBUUID UUIDWithString:servicerUUID];
        [self.centralManager scanForPeripheralsWithServices:@[servicesUUID] options:nil];
    }else {
        [self.centralManager scanForPeripheralsWithServices:nil options:nil];
    }
}

掃描到目標(biāo)藍(lán)牙設(shè)備時(shí),停止藍(lán)牙設(shè)備的掃描

    [self.centralManager stopScan];

連接目標(biāo)藍(lán)牙設(shè)備

    [self.centralManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@1}];

藍(lán)牙連接成功和失敗都有代理方法回調(diào)

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral timestamp:(CFAbsoluteTime)timestamp isReconnecting:(BOOL)isReconnecting error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central connectionEventDidOccur:(CBConnectionEvent)event forPeripheral:(CBPeripheral *)peripheral CB_CM_API_AVAILABLE;
- (void)centralManager:(CBCentralManager *)central didUpdateANCSAuthorizationForPeripheral:(CBPeripheral *)peripheral NS_AVAILABLE_IOS(13_0);

連接上目標(biāo)藍(lán)牙設(shè)備后,讀取藍(lán)牙服務(wù)數(shù)據(jù)和特征數(shù)據(jù)

- (void)discoverServices:(nullable NSArray<CBUUID *> *)serviceUUIDs;

讀取到服務(wù)后會(huì)調(diào)用對(duì)應(yīng)的代理方法

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error;

從服務(wù)中讀取特征值

- (void)discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;

找到特征后會(huì)出發(fā)找到特征的代理方法

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;

可以根據(jù)CBCharacteristic對(duì)象的characteristics數(shù)組,處理不同的特征服務(wù)。
類型如下:

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(10_9, 6_0)   = 0x100,
    CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x200
};

主要有CBCharacteristicPropertyRead、CBCharacteristicPropertyWrite、CBCharacteristicPropertyNotify。方便為讀、寫、通知。讀主要是讀取設(shè)備藍(lán)牙數(shù)據(jù),寫是向設(shè)備藍(lán)牙寫入數(shù)據(jù),通知是接收設(shè)備藍(lán)牙的通知。
讀取到特征值后會(huì)調(diào)用代理方法

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;

寫入特征值后也會(huì)調(diào)用代理方法告訴用戶是否寫入正確

 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;

訂閱狀態(tài)發(fā)生改變也會(huì)調(diào)用代理方法

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容