iOS藍牙開發(fā)小結(jié)

接觸iOS藍牙框架(CoreBluetooth)有一年多的時間了,遇到過很多問題,最近有空就想著記錄幾個自己覺得比較重要的知識點。

  1. 同一個iphone在搜索時對不同的藍牙設(shè)備會生成不同的UUID(universally unique identifier),當更換iphone去連接同一個設(shè)備時,需要重新搜索獲得新的UUID才能連接(調(diào)用下面的方法,傳入目的設(shè)備的UUID,如果得到的數(shù)組為空就需要重新搜索設(shè)備才能連接)
  • (NSArray<CBPeripheral >)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID >)identifiers NS_AVAILABLE(NA, 7_0);
    
    
  1. 不是連接過某個藍牙設(shè)備就表示iphone已記住這個設(shè)備(retrievePeripheralsWithIdentifiers:返回有效值,下一次可以快速重新連接),只有跟設(shè)備有過讀寫交互才會記住這個設(shè)備;

you cannot initiate pairing from the iOS central side. Instead, you have to read/write a characteristic value,and then let your peripheral respond with an "Insufficient Authentication" error.iOS will then initiate pairing, will store the keys for later use (bonding) and encrypts the link. As far as I know,it also caches discovery information, so that future connections can be set up faster.

  1. iOS8.0以上斷開手機藍牙時,會先響應(yīng)CBCentralManagerDelegate的藍牙連接斷開代理方法,再響應(yīng)藍牙狀態(tài)變更代理方法;iOS8.0以下斷開手機藍牙只響應(yīng)藍牙狀態(tài)變更代理方法;
藍牙連接斷開代理方法:
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
藍牙狀態(tài)變更代理方法:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
  1. 正常情況下需要設(shè)置一個定時器去處理連接藍牙設(shè)備和讀寫交互長時間無響應(yīng)的情況(如果在初始化centralManager的時候選擇在主線程做藍牙相關(guān)的操作,然后用NSTimer去處理這些無響應(yīng)的情況,這樣沒有問題),但大多數(shù)情況下藍牙的操作都是放在子線程去做的,為了實現(xiàn)多線程環(huán)境下timer的正常運行,一開始用的是NSThread+NSTimer的方式,timer正常工作了,但是timer沒被釋放掉,最終換成GCD的timer實現(xiàn)這個功能。
-(void)createConnectTimerWithInterval:(NSTimeInterval)interval timerHandler:(void (^)(void))timerHandler {
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      _connectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
      dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC));
      dispatch_source_set_timer(_connectTimer, start, (uint64_t)(0.1 * NSEC_PER_SEC), 0);
      dispatch_source_set_event_handler(_connectTimer, ^{
        timerHandler();
      });
      dispatch_resume(_connectTimer);
}
  1. 藍牙的操作步驟都是搜索->連接->獲取services和characteristics,這三個步驟完成之后才能進行讀寫交互;不同的藍牙設(shè)備攜帶不同services和characteristics,不同的characteristic也有不同的writeType,所以為了在一定程度上做到一勞永逸,自己寫了個配置文件:

    • 配置單個service
@interface WPBluetoothService : NSObject
-(instancetype)initWithServiceUUIDString:(NSString *)serviceUUIDString sendCharacteristicUUIDString:(NSString *)sendUUIDString receiveCharacteristicUUIDString:(NSString *)receiveUUIDString writeType:(CBCharacteristicWriteType)type;
@property (nonatomic, strong) CBUUID *serviceUUID;
@property (nonatomic, strong) CBUUID *sendCharacteristicUUID;
@property (nonatomic, strong) CBUUID *receiveCharacteristicUUID;
@property (nonatomic, strong) CBService *service;
@property (nonatomic, strong) CBCharacteristic *sendCharacteristic;
@property (nonatomic, strong) CBCharacteristic *receiveCharacteristic;
@property (nonatomic, assign) CBCharacteristicWriteType writeType;
-(BOOL)isAvailable;
- 配置整個藍牙設(shè)備攜帶的service
@interface WPBluetoothServiceProfile : NSObject
@property(nonatomic, strong) NSArray *bleServices;
@property(nonatomic, assign) BOOL batteryServiceEnable;
@property(nonatomic, assign) BOOL showSystemPowerAlert;
+(WPBluetoothServiceProfile *)sharedProfile;
-(WPBluetoothService *)serviceWithServiceUUID:(CBUUID *)uuid;
-(WPBluetoothService *)serviceWithSendCharacteristicUUID:(CBUUID *)uuid;
-(WPBluetoothService *)serviceWithReceiveCharacteristicUUID:(CBUUID *)uuid;
-(NSArray *)allServiceUUIDs;
-(void)resetAllServices;
-(BOOL)allServicesAvailable;

使用藍牙功能之前,只能配置每個WPBluetoothService對象的CBUUID類型的屬性,在連接成功成功后獲得services和characteristics成功才能填充剩下的屬性值。

-(void)configBluetoothService {
    NSMutableArray *services = [[NSMutableArray alloc] init];
    [services addObject: [[WPBluetoothService alloc] initWithServiceUUIDString:kCommandServiceId
                                                    sendCharacteristicUUIDString:kCommandSendCharacteristicUUIDString
                                                 receiveCharacteristicUUIDString:kCommandReceiveCharacteristicUUIDString
                                                                       writeType:CBCharacteristicWriteWithResponse]];
    
    [WPBluetoothServiceProfile sharedProfile].bleServices = services;
    [WPBluetoothServiceProfile sharedProfile].batteryServiceEnable = YES;
    [WPBluetoothServiceProfile sharedProfile].showSystemPowerAlert = YES;
}
發(fā)現(xiàn)services(僅貼核心代碼,省略一些基礎(chǔ)值的判斷):
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
         [[WPBluetoothServiceProfile sharedProfile] resetAllServices];
         for (CBService *service in services) {
           WPBluetoothService *bleService = [[WPBluetoothServiceProfile sharedProfile] serviceWithServiceUUID:service.UUID];
           if (bleService) {
             bleService.service = service;
             continue;
            }
           if ([service.UUID isEqual:[CBUUID UUIDWithString:kBatteryServiceId]]) {
             batteryServiceId = service;
           }
         }
         for (WPBluetoothService *bleService in [WPBluetoothServiceProfile sharedProfile].bleServices) {
             if (bleService.service) {
                  [peripheral discoverCharacteristics: [NSArray arrayWithObjects:bleService.sendCharacteristicUUID, bleService.receiveCharacteristicUUID, nil]
                                           forService:bleService.service];
              }
          }
}
發(fā)現(xiàn)characteristics(僅貼核心代碼,省略一些基礎(chǔ)值的判斷):
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error {
        WPBluetoothService *bleService = [[WPBluetoothServiceProfile sharedProfile] serviceWithServiceUUID:service.UUID];
        if(bleService) {
          for (CBCharacteristic *characteristic in characteristics) {
            if ([characteristic.UUID isEqual:bleService.receiveCharacteristicUUID]) {
                bleService.receiveCharacteristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            } else if ([characteristic.UUID isEqual:bleService.sendCharacteristicUUID]) {
                bleService.sendCharacteristic = characteristic;
            }
          }
        }
}

Related posts:

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

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

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