iOS蓝牙开发:蓝牙连接和数据读写

来源:互联网 发布:logo设计软件下载 编辑:程序博客网 时间:2024/05/21 12:46

当下蓝牙开发可谓是越来越火,不论是智能穿戴的兴起还是蓝牙家具,车联网蓝牙等等,很多同学也会接触到蓝牙的项目,我从事蓝牙开发也有一段时间了,经手了两个项目。废话不多说了,先向大家简单的介绍有关蓝牙开发的知识。蓝牙低能耗(BLE),以下介绍的都是围绕iOS的框架展开的。

蓝牙开发分为中心者模式和管理者模式:1.常用的(其实99.99%)就是使用中心者模式作为开发,就是我们手机作为主机,连接蓝牙外设;2.管理者模式,这个基本用到的比较少,我们手机自己作为外设,自己创建服务和特征,然后有其他的设备连接我们的手机。

在做蓝牙开发之前,最好先了解一些概念:
服务(services):蓝牙外设对外广播的必定会有一个服务,可能也有多个,服务下面包含着一些特征,服务可以理解成一个模块的窗口;
特征(characteristic):存在于服务下面的,一个服务下面也可以存在多个特征,特征可以理解成具体实现功能的窗口,一般特征都会有value,也就是特征值,特征是与外界交互的最小单位;
UUID:可以理解成蓝牙上的唯一标识符(硬件上肯定不是这个意思,但是这样理解便于我们开发),为了区分不同的服务和特征,或者给服务和特征取名字,我们就用UUID来代表服务和特征。

蓝牙连接可以大致分为以下几个步骤
1.建立一个Central Manager实例进行蓝牙管理
2.搜索外围设备
3.连接外围设备
4.获得外围设备的服务
5.获得服务的特征
6.从外围设备读数据
7.给外围设备发送数据
其他:提醒

首先我们先导入系统的BLE的框架

import

必须遵守2个协议

/* 中心管理者 /
@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 = , 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);}

}

6.从外围设备读数据

// 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否
- (void)peripheral:(CBPeripheral )peripheral didUpdateValueForCharacteristic:(CBCharacteristic )characteristic error:(NSError *)error
{
NSLog(@”%s, line = %d”, FUNCTION, LINE);
if (characteristic == @”你要的特征的UUID或者是你已经找到的特征”) {
//characteristic.value就是你要的数据
}
}

7.给外围设备发送数据(也就是写入数据到蓝牙)
这个方法你可以放在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,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含&
}

其他:提醒
有那么多的特征,我们怎么知道哪些特征是用来读数据的,哪些是用来写入的,哪些是需要订阅之后再读的呢?
如果你们硬件工程师事先告诉你了,或者有完成的开发文档,那么就可以直接知道了,否则你就需要自己去查看特征的属性,推介可以使用下第三方的app——LightBlue,让你更能清楚的看到你蓝牙里面的服务,特征,特征的属性。

其他后续有关文章,我会慢慢整理发出来,有需要的同学可以留下邮箱,我这里有视频教程,我也可以回答相关的问题,有错误的地方可以帮忙指出来呦!

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩脚痒怎么办小窍门 小孩肚子病怎么办天天说 幼儿园幼儿信息表填错了怎么办 水浒传书孩子说看不懂怎么办 孩子丢了书老师怎么办 小朋友做错事不承认老师怎么办 教师被学生骂后怎么办 嘴吧里面长泡怎么办 有个小孩怕下雨怎么办? 幼儿的家长打我怎么办 老师打学生被家长起诉怎么办 家长在学校打了老师怎么办 老师打小孩我们家长怎么办呢? 孩子长手、腿毛怎么办 腿毛又黑又多怎么办 孩子怕老师说他怎么办 被老师骂到厌学怎么办 孩子对写作业一点也不主动怎么办 高三孩子太贪玩怎么办 玩心重的孩子该怎么办 儿子读大学不愿意读书怎么办 孩子打架全班都讨厌怎么办 孩子不爱学习怎么办 二年级 二年级孩子不爱学习总爱玩怎么办 初三孩子学习不积极怎么办 孩子学习不积极应该怎么办 小孩子贪玩不写作业怎么办 老公懒不帮忙分担家务怎么办 宝宝不喜欢早教课程单一怎么办 孩子上课不听话顶撞老师怎么办 孩子不喜欢吃水果蔬菜怎么办 中学生顶撞家长顶撞老师怎么办 .cn孩子初中上课不专心怎么办 娃儿小学二年级做不来怎么办 孩子不愿意看书沉迷电子产品怎么办 孩子自律和自控性差怎么办 婴儿7个月不喜欢吃东西怎么办 半岁宝宝太活泼怎么办 6个月宝宝太活泼怎么办 做nt宝宝太活跃怎么办 静不下心来学习怎么办