当下蓝牙开发可谓是越来越火,不论是智能穿戴的兴起还是蓝牙家具,车联网蓝牙等等,很多同学也会接触到蓝牙的项目,我从事蓝牙开发也有一段时间了,经手了两个项目。废话不多说了,先向大家简单的介绍有关蓝牙开发的知识。蓝牙低能耗(BLE),以下介绍的都是围绕iOS的 CoreBluetooth/CoreBluetooth.h 框架展开的。
目前成都创新互联公司已为近1000家的企业提供了网站建设、域名、虚拟空间、网站运营、企业网站设计、上饶网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
蓝牙开发分为中心者模式和管理者模式:1.常用的(其实99.99%)就是使用中心者模式作为开发,就是我们手机作为主机,连接蓝牙外设;2.管理者模式,这个基本用到的比较少,我们手机自己作为外设,自己创建服务和特征,然后有其他的设备连接我们的手机。
在做蓝牙开发之前,最好先了解一些概念:
服务(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实例进行蓝牙管理
2.搜索外围设备 (我这里为了举例,采用了自己身边的一个手环)
3.连接外围设备
4.获得外围设备的服务 5.获得服务的特征
6.从外围设备读数据
7.给外围设备发送数据(也就是写入数据到蓝牙)
这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用啦
其他:提醒
有那么多的特征,我们怎么知道哪些特征是用来读数据的,哪些是用来写入的,哪些是需要订阅之后再读的呢?
如果你们硬件工程师事先告诉你了,或者有完成的开发文档,那么就可以直接知道了,否则你就需要自己去查看特征的属性,推介可以使用下第三方的app——LightBlue,让你更能清楚的看到你蓝牙里面的服务,特征,特征的属性。
其他后续有关文章,我会慢慢整理发出来,我也可以回答相关的问题,有错误的地方可以帮忙指出来呦!
蓝牙开发说简单也简单,说不简单也有点难,开发人员在首次开发蓝牙前首先需要搞清楚蓝牙开发的概念,还要了解掌握蓝牙开发的一整套流程,这样才能快速上手开发蓝牙。
蓝牙开发分为两种模式:管理者模式和中心者模式。管理者模式基本很少用到,相当于iPhone手机作为外设,自己创建服务和特性,然后用其他设备连接iPhone手机;中心者模式一般是大部分情况下都会使用的,使用中心者模式开发相当于iPhone手机作为主机,连接蓝牙外设,下面介绍蓝牙开发的例子就是使用的中心者模式来讲解的。
在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,我欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程
一、关于蓝牙开发的一些重要的理论概念:
1、服务(services):蓝牙外设对外广播的时候一定会有一个服务,有些时候也可以是有多个服务,服务下面包含一些特性,服务可以理解成一个模块的窗口;
2、特征(characteristic):特征存在于服务下面的,一个服务下面可以有多个特征,特征可以理解成具体实现功能的窗口,一般的特性都会有value,也就是特征值,是特征和外界交互的最小单位;
3、UUID:蓝牙上的唯一标示符,为了区分不同服务和特征,就用UUID来表示。
二、蓝牙连接的主要步骤
1、创建一个CBCentralManager实例来进行蓝牙管理;
2、搜索扫描外围设备;
3、连接外围设备;
4、获得外围设备的服务;
5、获得服务的特征;
6、从外围设备读取数据;
7、给外围设备发送(写入)数据。
三、蓝牙连接和数据读写的具体步骤
1、导入苹果系统蓝牙框架
#import
2、遵循两个蓝牙框架相关的协议
3、新建两个实例属性,一个特征属性
@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral; //连接到的外设
@property (nonatomic, strong) CBCharacteristic *characteristic; //特征
4、初始化CBCentralManager,进行蓝牙管理
- (void)viewDidLoad {
[super viewDidLoad];
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; //创建实例进行蓝牙管理
}
//若中心管理者初始化之后 就会触发下面这个代理方法 该代理方法是用来判断手机蓝牙的状态的
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// 蓝牙可用,开始扫描外设
if (central.state == CBManagerStatePoweredOn) {
NSLog(@"蓝牙可用");
//在中心管理者成功开启之后再进行一些操作
//搜索扫描外设
// 根据SERVICE_UUID来扫描外设,如果不设置SERVICE_UUID,则扫描所有蓝牙设备
// [self.centralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:SERVICE_UUID]]}];
[central scanForPeripheralsWithServices:nil options:nil];
}
if(central.state == CBManagerStateUnsupported) {
NSLog(@"该设备不支持蓝牙");
}
if (central.state == CBManagerStatePoweredOff) {
NSLog(@"蓝牙已关闭");
}
if (central.state == CBManagerStateUnknown) {
NSLog(@"蓝牙当前状态不明确");
}
if (central.state == CBManagerStateUnauthorized) {
NSLog(@"蓝牙未被授权");
}
}
5、搜索外围设备
//执行扫描动作之后,如果扫描到外设了,就会自动回调下面的协议方法
/** 发现符合要求的外设,回调 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"%@====",peripheral.name);
//根据外设名字有选择性的筛选连接蓝牙设备
if ([peripheral.name hasPrefix:@"TEAMOSA"]) {
//在这里对外设携带的广播数据进行进一步的处理
if ([self.peripheraNames containsObject:peripheral.name]) {
//如果数组中包含了就不再添加
return;
}
//添加到外设名字数组中
[self.peripheraNames addObject:peripheral.name];
//标记外设,让它的生命周期与控制器的一致
self.peripheral = peripheral;
// 可以根据外设名字来过滤外设
// [central connectPeripheral:peripheral options:nil];
}
// 连接外设
// [central connectPeripheral:peripheral options:nil];
}
6、连接外围设备
//连接外围设备,中心管理者连接外设成功,如果连接成功就会回调这个协议方法
/** 连接成功 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
//连接成功之后,可以进行服务和特性的发现。 停止中心管理设备的扫描动作,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的iOS设备也会去连接这个设备(因为iOS BLE4.0是支持一对多连接的),导致数据的混乱。
//停止扫描动作
[self.centralManager stopScan];
// 设置外设的代理
peripheral.delegate = self;
// 根据UUID来寻找服务
// [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
//外设发现服务,传nil代表不过滤,一次性读出外设的所有服务
[peripheral discoverServices:nil];
NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name);
}
//外设连接失败
/** 连接失败的回调 */
- (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:(nullable NSError *)error {
NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);
// 断开连接可以设置重新连接
[central connectPeripheral:peripheral options:nil];
}
7、获取外围设备服务和特征
/** 发现服务 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// 遍历出外设中所有的服务
for (CBService *service in peripheral.services) {
// NSLog(@"所有的服务:%@",service);
}
// 这里仅有一个服务,所以直接获取
CBService *service = peripheral.services.lastObject;
// 根据UUID寻找服务中的特征
// [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC_UUID]] forService:service];
// [peripheral discoverCharacteristics:@[service.UUID] forService:service];
[peripheral discoverCharacteristics:nil forService:service];
}
8、从外围设备读取数据
// 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否 从外围设备读数据
/** 接收到数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// if (characteristic == @"你要的特征的UUID或者是你已经找到的特征") {
// //characteristic.value就是你要的数据
// }
if ([peripheral.name hasPrefix:@"TEAMOSA"]){
NSData *data = characteristic.value;
NSString *value = [self hexadecimalString:data];
// NSLog(@"characteristic(读取到的): %@, data : %@, value : %@", characteristic, data, value);
}
// 拿到外设发送过来的数据
// NSData *data = characteristic.value;
// self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
9、向外围设备发送(写入)数据
//这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用
//[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];//第一个参数是已连接的蓝牙设备; 第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入 需要注意的是特征的属性是否支持写数据
/** 写入数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
/*
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,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含
NSLog(@"write value success(写入成功) : %@", characteristic);
}
10、具体调用给蓝牙外设写入数据方法,这里的例子是以按钮点击事件里面来调用处理
//发送按钮点击事件
- (void)sendClick {
if (!self.characteristic) {
return;
}
_tempValue = [NSString stringWithFormat:@"%.0f", progressView.centigradeDegree];
_timeValue = [NSString stringWithFormat:@"%.0ld", (long)progressView1.timeDegree];
NSString *ttData = [NSString stringWithFormat:@"%@,%@U", _tempValue, _timeValue];
// NSString *aaa = [DataCoverTool coverFromStringToHexStr:ttData];
// 用NSData类型来写入
// NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arry];
NSData *data = [ttData dataUsingEncoding:NSUTF8StringEncoding];
// NSData *data = [self dataWithString:ttData];
// 根据上面的特征self.characteristic来写入数据
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
1 AirDrop (UIActivityViewController类)
功能:实现iOS设备间的文件和数据分享。AirDrop使用蓝牙来扫描周围的设备,当两台设备通过蓝牙建立起了连接,考虑到更快速的数据传输,它就会创建点对点的WiFi网络来连接两部iOS 设备。但并不意味着为了使用AirDrop而需要把设备连接至WiFi网络。
传输方式:蓝牙、WiFi
支持系统:iOS
2 GameKit 框架
功能:GameKit主要是完成iOS设备间联网的相关功能,包括蓝牙和Internet两种方式。
传输方式:蓝牙、WiFi
支持系统:iOS
3 MultipeerConnectivity 框架
功能:利用Multipeer Connectivity框架,即使在没有连接到WiFi(WLAN)或移动网络(xG)的情况下,距离较近的Apple设备(iMac/iPad/iPhone)之间可基于蓝牙和WiFi(P2P WiFi)技术进行发现和连接实现近场通信。
传输方式:蓝牙、WiFi
支持系统:iOS
4 ExternalAccessory 框架
功能:External Accessory Framework提供了配件连接iOS设备的通道。开发者可以通过它来开发连接配件的app。配件可以通过30pin、蓝牙、USB的方式连接iOS设备。
传输方式:蓝牙、WiFi
支持系统:iOS
5 CoreBluetooth 框架
功能:蓝牙4.0协议之间信息传输,支持iOS和Android设备。
传输方式:蓝牙
支持系统:iOS、Android
6 Socket
功能:通过TCP或UDP进行相同局域网内信息传输,支持iOS和Android设备。
传输方式:WiFi
支持系统:iOS、Android
7 Bonjour
功能:Bonjour是一种能够自动查询接入网络中的设备或应用程序的协议。Bonjour 抽象掉 ip 和 port 的概念,让我们聚焦于更容易为人类思维理解的 service。通过 Bonjour,一个应用程序 publish 一个网络服务 service,然后网络中的其他程序就能自动发现这个 service,从而可以向这个 service 查询其 ip 和 port,然后通过获得的 ip 和 port 建立 socket 链接进行通信,支持iOS和Android设备。
传输方式:WiFi
支持系统:iOS、Android
8 AllJoyn
功能:AllJoyn,由高通公司主导的高创新中心的开源项目开发的,主要用于近距离无线传输,通过WiFi或蓝牙技术,定位和点对点文件传输。支持平台:RTOS、Arduino、Linux、Android、iOS、Windows、Mac。
传输方式:蓝牙、WiFi
支持系统:RTOS、Arduino、Linux、Android、iOS、Windows、Mac
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款