iOS蓝牙开发(bluetooth)

蓝牙库( 4.0 BLE )

苹果自身有一个操作蓝牙的库 CoreBluetooth.framework,这是 大部分人进行蓝牙开发的首选框架。
除此之外,目前github上还有一个比较流行的对原生框架进行封装的三方库 BabyBluetooth

蓝牙设备版本要求

蓝牙设备必须是4.0及以上.
BLE : bluetouch low enery,蓝牙4.0设备因为低功耗,所以也被称为BLE。苹果在 iphone4s 及之后的手机都支持蓝牙4.0。
低于蓝牙4.0协议的设备需要进行MFI认证
MFI : make for ipad, iphone, itouch 专门为苹果设备制作的设备
MFI : 开发框架为 ExternalAccessory 框架
BLE 4.0 : 开发框架为 CoreBluetooth 框架

蓝牙知识 ( 主讲中心模式,外设暂未开发留作以后补充 )

蓝牙处理是16进制,并且每次传输最多是20个字节
CoreBluetooth 框架主要核心部分就是两个,peripheral 和 central。
发起连接的是中心设备,被连接的是外围设备。
中心模式:以app作为中心,连接其他外设的场景
外设模式:使用手机作为外设连接其他中心设备的操作场景

服务,特征,特征的属性(service and characteristic)

一个外设可以包含一个或多个服务(CBService),一个服务又包含一个或多个特征(CBCharacteristic),特征就是具体功能的键值对,提供数据的地方。每个特征的属性分为:通知,读,写这几种方式

外设,服务,特征之间的关系如下:


关系图

蓝牙中心模式流程 ( 以BabyBluetooth为例 )

1.初始化中心设备管理者:CBCentralManager
/**
将蓝牙模块进行封装单例
初始化蓝牙设置蓝牙中心设备
*/
+ (instancetype)shareBaby {
    
    static BabyBlueToothManager *babyBluetooth;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!babyBluetooth) {
            babyBluetooth = [[self class] alloc];
            // 提示蓝牙功能开启
            NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};
            babyBluetooth.centeralManager = [[CBCentralManager alloc] initWithDelegate:babyBluetooth queue:nil options:options];
            
            // 初始化 baby 蓝牙库
            babyBluetooth.baby = [BabyBluetooth shareBabyBluetooth];
            // 设置蓝牙代理
            [babyBluetooth babyDelegate];
           //babyBluetooth.baby.scanForPeripherals().begin();
        }
    });
    return babyBluetooth;
}
2.扫描外围设备
[BabyBlueToothManager shareBaby].baby.scanForPeripherals().begin();
3.扫描结果通过CBCentralManagerDelegate代理进行回调,这里BabyBluetooth进行block块封装
/**
搜索设备获取中心设备,
外设
外设advertisementData数据(广告数据),通常情况下mac地址会存储在这里
RSSI为信号强度
*/
[_baby setBlockOnDiscoverToPeripherals:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) {
        NSLog(@"搜索到了设备:%@",peripheral.name);
        @strongify_self
    
    }];
/**
获取外设后,对外设进行过滤,筛选符合规则的蓝牙设备
*/
[_baby setFilterOnDiscoverPeripherals:^BOOL(NSString *peripheralName, NSDictionary *advertisementData, NSNumber *RSSI) {
        //判断设备,通过相应规则搜索出的设备会显示在  BlockOnDiscoverToPeripherals 这个方法中
        if (peripheralName.length >1) {
            if ([advertisementData[@"kCBAdvDataLocalName"] hasPrefix:@"Pxxxxx"] || [advertisementData[@"kCBAdvDataLocalName"] hasPrefix:@"Sxxxx"]) {
                return YES;
            }
        }
        return NO;
    }];
4.连接设备并断开搜索
/**
 连接蓝牙
 */

- (void)connetBlueToothWithCBPeripheral:(CBPeripheral *)peripheral {
    
// 连接外设.发现服务.发现特征.读取特征数据.发现特征数据(键值对).读取特征描述.开始连接
self.baby.having(peripheral).connectToPeripherals().discoverServices().discoverCharacteristics().readValueForCharacteristic().discoverDescriptorsForCharacteristic().readValueForDescriptors().begin();  
// 取消搜索蓝牙
    [self.baby cancelScan];

}
5.设备连接状态回调
// 设备连接成功
    [_baby setBlockOnConnected:^(CBCentralManager *central, CBPeripheral *peripheral) {
        NSLog(@"设备:%@--连接成功",peripheral.name);
        @strongify_self
    }];

//设置设备连接失败的委托
    [_baby setBlockOnFailToConnect:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--连接失败",peripheral.name);
        [GGProgress showProgressWithTitle:@"设备连接失败"];
    }];

//设置设备断开连接的委托
    [_baby setBlockOnDisconnect:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--断开连接",peripheral.name);
        @strongify_self
        // 这里可以处理重新连接
    }];
6.连接成功后发现设备服务(service)
// 发现设备服务
 [_baby setBlockOnDiscoverServices:^(CBPeripheral *peripheral, NSError *error) {
        for (CBService *s in peripheral.services) {
            //每个service
        }
    }];
//设置发现设service的Characteristics的委托
    [_baby setBlockOnDiscoverCharacteristics:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
        NSLog(@"===service name:%@",service.UUID);
        [service.characteristics enumerateObjectsUsingBlock:^(CBCharacteristic * _Nonnull characteristic, NSUInteger idx, BOOL * _Nonnull stop) {
            // 通过枚举获取服务特征
            NSLog(@"aaaaaaaa    %@ \n %lu ", characteristic.UUID , (unsigned long)characteristic.properties);
        }];
    }];
 //设置发现characteristics的descriptors的委托
    [_baby setBlockOnDiscoverDescriptorsForCharacteristic:^(CBPeripheral *peripheral, CBCharacteristic *characteristic, NSError *error) {
        NSLog(@"===characteristic name:%@",characteristic.service.UUID);
        for (CBDescriptor *d in characteristic.descriptors) {
            NSLog(@"CBDescriptor name is :%@",d.UUID);
        }
    }];
7.读取设备服务-特征的数据
  [_baby setBlockOnReadValueForCharacteristic:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
        // 
        @strongify_self
        CBUUID *uuid = characteristics.UUID;
        if ([uuid.UUIDString isEqualToString:@"xxxx"]) {
            // 如果是想要的服务特征 则赋值到 相对应的 外设及 特征中,进行数据交互
            self.characteristic = characteristics;
            self.peripheral = peripheral;
        }
    }];
8.读取特征的数据描述(键值对),注册特征通知,中心设备读取外设外围所发送过来的数据
   //设置读取Descriptor的委托
       [_baby setBlockOnReadValueForDescriptors:^(CBPeripheral *peripheral, CBDescriptor *descriptor, NSError *error) {
        @strongify_self
        CBUUID *uuid = descriptor.characteristic.UUID;
        CBCharacteristic *charach = descriptor.characteristic;
        NSData *data = charach.value;
        //  判断是否是当前设备
        if ([[BlueToothInfo shareBlueToothInfo].localName isEqualToString:@"xxxx"]) {
            // 获取 所要获取的特征
            if ([uuid.UUIDString isEqualToString:@"xxxx"]) {
                self.characteristic = descriptor.characteristic;
                self.peripheral = peripheral;
            }else {
                // 进行注册特征通知,获取外围数据
                [self.baby notify:peripheral characteristic:descriptor.characteristic block:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
                    @strongify_self
                     // 收到的指令数据
                    NSData *wineData = characteristics.value;
                    // 16进制数据转换,判断指令
                    NSString *str16 = [self convertDataToHexStr:wineData];
                }];
            }
        }
        NSLog(@"Descriptor name:%@ value is:%@\n %@",descriptor.characteristic.UUID, descriptor.value, data);
    }];
9.处理数据(数据接收结束)。以下为向外围设备发送数据
/** 通过单例 获取当前外设, 通过特征值进行写入操作
data 通过 NSASCIIStringEncoding ASCII进行转换,蓝牙接收数据为16进制
 writeType 分为两种
1.CBCharacteristicWriteWihResponse(写成功一次,只可读)即有反馈
2.CBCharacteristicWriteWithoutResponse(一次也不能写成功,可以读,也可以通知)即无反馈
*/
[[BabyBlueToothManager shareBaby].peripheral writeValue:data forCharacteristic:[BabyBlueToothManager shareBaby].characteristic type:writeType];
// 写入的数据 均在 步骤 8中的 notify 回调中 回调数据
10.写入成功与否的回调
//写Characteristic成功后的block
 [_baby setBlockOnDidWriteValueForCharacteristic:^(CBCharacteristic *characteristic, NSError *error) {
        // error判断 写入特征是否成功,自行处理
    }];
//写descriptor成功后的block
[_baby setBlockOnDidWriteValueForDescriptor:^(CBDescriptor *descriptor, NSError *error) {
         // error判断 写入特征描述数据是否成功,自行处理
    }];
11.断开连接
//断开连接
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral {
    [babyCentralManager cancelPeripheralConnection:peripheral];
}
//断开所有连接
- (void)cancelAllPeripheralsConnection {
    [babyCentralManager cancelAllPeripheralsConnection];
}

如有疑问可以探讨,如有错误可以指正,欢迎补充,感谢支持🙏

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

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,561评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,205评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,690评论 2 7