iOS蓝牙开发小结

接触iOS蓝牙框架(CoreBluetooth)有一年多的时间了,遇到过很多问题,最近有空就想着记录几个自己觉得比较重要的知识点。

  1. 同一个iphone在搜索时对不同的蓝牙设备会生成不同的UUID(universally unique identifier),当更换iphone去连接同一个设备时,需要重新搜索获得新的UUID才能连接(调用下面的方法,传入目的设备的UUID,如果得到的数组为空就需要重新搜索设备才能连接)
  • (NSArray<CBPeripheral >)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID >)identifiers NS_AVAILABLE(NA, 7_0);
    
    
  1. 不是连接过某个蓝牙设备就表示iphone已记住这个设备(retrievePeripheralsWithIdentifiers:返回有效值,下一次可以快速重新连接),只有跟设备有过读写交互才会记住这个设备;

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以上断开手机蓝牙时,会先响应CBCentralManagerDelegate的蓝牙连接断开代理方法,再响应蓝牙状态变更代理方法;iOS8.0以下断开手机蓝牙只响应蓝牙状态变更代理方法;
蓝牙连接断开代理方法:
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
蓝牙状态变更代理方法:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
  1. 正常情况下需要设置一个定时器去处理连接蓝牙设备和读写交互长时间无响应的情况(如果在初始化centralManager的时候选择在主线程做蓝牙相关的操作,然后用NSTimer去处理这些无响应的情况,这样没有问题),但大多数情况下蓝牙的操作都是放在子线程去做的,为了实现多线程环境下timer的正常运行,一开始用的是NSThread+NSTimer的方式,timer正常工作了,但是timer没被释放掉,最终换成GCD的timer实现这个功能。
-(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,这三个步骤完成之后才能进行读写交互;不同的蓝牙设备携带不同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;
- 配置整个蓝牙设备携带的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;
}
发现services(仅贴核心代码,省略一些基础值的判断):
-(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];
              }
          }
}
发现characteristics(仅贴核心代码,省略一些基础值的判断):
-(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:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 在写这个博客之前,空余时间抽看了近一个月的文档和Demo,系统给的解释很详细,接口也比较实用,唯独有一点,对于设备...
    木易林1阅读 3,353评论 3 4
  • 本文主要以蓝牙4.0做介绍,因为现在iOS能用的蓝牙也就是只仅仅4.0的设备 用的库就是core bluetoot...
    暮雨飞烟阅读 840评论 0 2
  • 在.m文件中 #import"ViewController.h"#import"NSString+SL_Exten...
    李炯7115阅读 811评论 0 0
  • 原文:http://www.myexception.cn/operating-system/2052286.htm...
    KYM1988阅读 1,944评论 2 2
  • 9.5五点四十分起床洗衣晒衣后,叫老大起床,少休息后叫老二起床。到房地局做房查,下午提前下班回家干完家务到八点,找...
    天空依依阅读 142评论 0 0