iOS蓝牙开发 蓝牙连接和数据读写
在做蓝牙开发之前,最好先了解一些概念:
服务(services):蓝牙外设对外广播的必定会有一个服务,可能也有多个,服务下面包含着一些特征,服务可以理解成一个模块的窗口;
特征(characteristic):存在于服务下面的,一个服务下面也可以存在多个特征,特征可以理解成具体实现功能的窗口,一般特征都会有value,也就是特征值,特征是与外界交互的最小单位;
uuid:可以理解成蓝牙上的唯一标识符(硬件上肯定不是这个意思,但是这样理解便于我们开发),为了区分不同的服务和特征,或者给服务和特征取名字,我们就用uuid来代表服务和特征。
蓝牙连接可以大致分为以下几个步骤
1.建立一个central manager实例进行蓝牙管理
2.搜索外围设备
3.连接外围设备
4.获得外围设备的服务
5.获得服务的特征
6.从外围设备读数据
7.给外围设备发送数据
其他:提醒
首先我们先导入系统的ble的框架
#import <corebluetooth/corebluetooth.h>
必须遵守2个协议
<cbcentralmanagerdelegate, cbperipheraldelegate>
/** 中心管理者 */
@property (nonatomic, strong) cbcentralmanager *cmgr;
/** 连接到的外设 */
@property (nonatomic, strong) cbperipheral *peripheral;
1.建立一个central manager实例进行蓝牙管理
-(cbcentralmanager *)cmgr { if (!_cmgr) { _cmgr = [[cbcentralmanager alloc] initwithdelegate:self queue:nil]; } return _cmgr; } //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态 - (void)centralmanagerdidupdatestate:(cbcentralmanager *)central { switch (central.state) { case 0: nslog(@"cbcentralmanagerstateunknown"); break; case 1: nslog(@"cbcentralmanagerstateresetting"); break; case 2: nslog(@"cbcentralmanagerstateunsupported");//不支持蓝牙 break; case 3: nslog(@"cbcentralmanagerstateunauthorized"); break; case 4: { nslog(@"cbcentralmanagerstatepoweredoff");//蓝牙未开启 } break; case 5: { nslog(@"cbcentralmanagerstatepoweredon");//蓝牙已开启 // 在中心管理者成功开启后再进行一些操作 // 搜索外设 [self.cmgr scanforperipheralswithservices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 // 搜索成功之后,会调用我们找到外设的代理方法 // - (void)centralmanager:(cbcentralmanager *)central diddiscoverperipheral:(cbperipheral *)peripheral advertisementdata:(nsdictionary *)advertisementdata rssi:(nsnumber *)rssi; //找到外设 } break; default: break; } }
2.搜索外围设备 (我这里为了举例,采用了自己身边的一个手环)
// 发现外设后调用的方法 - (void)centralmanager:(cbcentralmanager *)central // 中心管理者 diddiscoverperipheral:(cbperipheral *)peripheral // 外设 advertisementdata:(nsdictionary *)advertisementdata // 外设携带的数据 rssi:(nsnumber *)rssi // 外设发出的蓝牙信号强度 { //nslog(@"%s, line = %d, cetral = %@,peripheral = %@, advertisementdata = %@, rssi = %@", __function__, __line__, central, peripheral, advertisementdata, rssi); /* peripheral = <cbperipheral: 0x166668f0 identifier = c69010e7-eb75-e078-ffb4-421b4b951341, name = "oband-75", state = disconnected>, advertisementdata = { kcbadvdatachannel = 38; kcbadvdataisconnectable = 1; kcbadvdatalocalname = oband; kcbadvdatamanufacturerdata = <4c69616e 0e060678 a5043853 75>; kcbadvdataserviceuuids = ( fee7 ); kcbadvdatatxpowerlevel = 0; }, rssi = -55 根据打印结果,我们可以得到运动手环它的名字叫 oband-75 */ // 需要对连接到的外设进行过滤 // 1.信号强度(40以上才连接, 80以上连接) // 2.通过设备名(设备字符串前缀是 oband) // 在此时我们的过滤规则是:有oband前缀并且信号强度大于35 // 通过打印,我们知道rssi一般是带-的 if ([peripheral.name hasprefix:@"oband"]) { // 在此处对我们的 advertisementdata(外设携带的广播数据) 进行一些处理 // 通常通过过滤,我们会得到一些外设,然后将外设储存到我们的可变数组中, // 这里由于附近只有1个运动手环, 所以我们先按1个外设进行处理 // 标记我们的外设,让他的生命周期 = vc self.peripheral = peripheral; // 发现完之后就是进行连接 [self.cmgr connectperipheral:self.peripheral options:nil]; nslog(@"%s, line = %d", __function__, __line__); } }
3.连接外围设备
// 中心管理者连接外设成功 - (void)centralmanager:(cbcentralmanager *)central // 中心管理者 didconnectperipheral:(cbperipheral *)peripheral // 外设 { nslog(@"%s, line = %d, %@=连接成功", __function__, __line__, peripheral.name); // 连接成功之后,可以进行服务和特征的发现 // 设置外设的代理 self.peripheral.delegate = self; // 外设发现服务,传nil代表不过滤 // 这里会触发外设的代理方法 - (void)peripheral:(cbperipheral *)peripheral diddiscoverservices:(nserror *)error [self.peripheral discoverservices:nil]; } // 外设连接失败 - (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); }
4.获得外围设备的服务 & 5.获得服务的特征
// 发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道uuid找到你需要的特征,订阅特征,或者这里写入数据给特征也可以) - (void)peripheral:(cbperipheral *)peripheral diddiscovercharacteristicsforservice:(cbservice *)service error:(nserror *)error { nslog(@"%s, line = %d", __function__, __line__); for (cbcharacteristic *cha in service.characteristics) { //nslog(@"%s, line = %d, char = %@", __function__, __line__, cha); } }
5.从外围设备读数据
// 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否 - (void)peripheral:(cbperipheral *)peripheral didupdatevalueforcharacteristic:(cbcharacteristic *)characteristic error:(nserror *)error { nslog(@"%s, line = %d", __function__, __line__); if (characteristic == @"你要的特征的uuid或者是你已经找到的特征") { //characteristic.value就是你要的数据 } }
6.给外围设备发送数据(也就是写入数据到蓝牙)
这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用啦
[self.peripherale writevalue:_batterydata forcharacteristic:self.characteristic type:cbcharacteristicwritewithresponse]; //第一个参数是已连接的蓝牙设备 ;第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入
// 需要注意的是特征的属性是否支持写数据 - (void)yf_peripheral:(cbperipheral *)peripheral didwritedata:(nsdata *)data forcharacteristic:(nonnull cbcharacteristic *)characteristic { /* 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(na, 6_0) = 0x100, cbcharacteristicpropertyindicateencryptionrequired ns_enum_available(na, 6_0) = 0x200 }; 打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个ns_options的枚举,可以是多个值 常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式 */ // nslog(@"%s, line = %d, char.pro = %d", __function__, __line__, characteristic.properties); // 此时由于枚举属性是ns_options,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含& }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 如何恢复MYSQL的ROOT口令
下一篇: Access数据库的存储上限