iOS开发 蓝牙功能

iOS开发蓝牙功能主要分扫描中心和外设设备

Central中心设备,发起蓝牙连接的设备(一般指手机)
Peripheral: 外设,被蓝牙连接的设备(一般是运动手环/蓝牙模块)
Service:服务,每个设备会提供服务,一个设备有很多服务
Characteristic:特征,每个服务中包含很多个特征,这些特征的权限一般分为:读(read)/写(write)/通知(notice)几种,可以通过特征进行读写数据(重要角色)(中心设备写入数据的时候一定要找到可写入特征才可以写入成功)
Descriptor:描述者,每个特征可以对应一个或者多个描述者,用于描述特征的信息或者属性

准备工作,iOS设备,接入#import <CoreBluetooth/CoreBluetooth.h>,一台手机作为中心设备,一台手机作为外设(或者蓝牙设备硬件),外安装一个蓝牙调试助手作为辅助工具,查找那些特征是可写,可读等等。

以下是流程代码

1.中心设备开启扫描,调用即可[self mCentral];

- (CBCentralManager *)mCentral
{if (!_mCentral) {_mCentral = [[CBCentralManager alloc] initWithDelegate:selfqueue:dispatch_get_main_queue()options:nil];}return _mCentral;
}

2.中心设备初始化后,调用以下代理方法(必须实现的)

//2、只要中心管理者初始化,就会触发此代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{switch (central.state) {case CBManagerStateUnknown:NSLog(@"CBCentralManagerStateUnknown");break;case CBManagerStateResetting:NSLog(@"CBCentralManagerStateResetting");break;case CBManagerStateUnsupported:NSLog(@"CBCentralManagerStateUnsupported");break;case CBManagerStateUnauthorized:NSLog(@"CBCentralManagerStateUnauthorized");break;case CBManagerStatePoweredOff:NSLog(@"CBCentralManagerStatePoweredOff");break;case CBManagerStatePoweredOn:{NSLog(@"CBCentralManagerStatePoweredOn");//3、搜索外设[self.mCentral scanForPeripheralsWithServices:nil // 通过某些服务筛选外设options:nil]; // dict,条件}break;default:break;}
}

3.发现外部设备后(蓝牙设备)的回调方法

//4、发现外设后调用的方法
- (void)centralManager:(CBCentralManager *)central // 中心管理者didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设advertisementData:(NSDictionary *)advertisementData // 外设携带的数据RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度
{if (peripheral.name) {[self.dataArr addObject:peripheral];}[self.tableView reloadData];//(ABS(RSSI.integerValue) > 35)//5、发现完之后就是进行连接if([peripheral.name isEqualToString:mBLEName]){self.mPeripheral = peripheral;self.mPeripheral.delegate = self;[self.mCentral connectPeripheral:peripheral options:nil];}
}

4.确定要连接哪个蓝牙设备(我这里用的是tableView显示发现的外部蓝牙设备,所以在这个代理方法里面点击具体某个设备即可)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{CBPeripheral *per = self.dataArr[indexPath.row];self.mPeripheral = per;self.mPeripheral.delegate = self;[self.mCentral connectPeripheral:per options:nil];
}

5.中心设备链接外部设备成功,失败,丢失的回调方法,如果需要自动重连,可以失败,丢失接口里面重新调用连接


//6、中心管理者连接外设成功
- (void)centralManager:(CBCentralManager *)central // 中心管理者didConnectPeripheral:(CBPeripheral *)peripheral // 外设
{NSLog(@"%@==设备连接成功", peripheral.name);//7、外设发现服务,传nil代表不过滤[self.mPeripheral discoverServices:nil];
}// 外设连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{NSLog(@"设备连接失败==%@", peripheral.name);
}// 丢失连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{NSLog(@"设备丢失连接==%@", peripheral.name);
}

6.连接蓝牙成功以后实现以下回调,查找我们需要的特征,跟进具体某个特征是否可写,可读,进行记录,后续作为写入和读取数据使用(查询是否可写可读时可以手机安装一个蓝牙调试助手查看)

//8、发现外设的服务后调用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{// 是否获取失败if (error) {NSLog(@"备获取服务失败==%@", peripheral.name);return;}for (CBService *service in peripheral.services) {self.mService = service;NSLog(@"发现外设的服务后调用的方法 设备的服务==%@,UUID==%@,count==%lu",service,service.UUID,peripheral.services.count);//9、外设发现特征[peripheral discoverCharacteristics:nil forService:service];}
}//10、发现外设特征的时候调用的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{//这里面校验哪些特征值是可写或者可读 ,这里可以使用手机端搜索蓝牙调试助手,查看哪些特征服务可写for (CBCharacteristic *cha in service.characteristics) {if([cha.UUID.UUIDString isEqualToString:@"8667556C-9A37-4C91-84ED-54EE27D90049"]){//找到可写的特征self.mCharacteristic = cha;NSLog(@"从服务中发现外设特征的时候调用的代理方法设备的服务==%@,服务对应的特征值==%@,UUID==%@---%@,",service,cha,cha.UUID,cha.UUID.UUIDString);//11、获取特征对应的描述 会回调didUpdateValueForDescriptor[peripheral discoverDescriptorsForCharacteristic:cha];//12、获取特征的值 会回调didUpdateValueForCharacteristic[peripheral readValueForCharacteristic:cha];//打开外设的通知,否则无法接受数据[peripheral setNotifyValue:YES forCharacteristic:self.mCharacteristic];}}}//13、更新描述值的时候会调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{NSLog(@"描述==%@",descriptor.description);
}//14、更新特征值的时候调用,可以理解为获取蓝牙发回的数据 获取外设发来的数据,不论是read和notify,获取数据都从这个方法中读取
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{NSData* data = characteristic.value;NSString* value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"uuid:%@ value : %@",characteristic.UUID,value);
}//15、通知状态改变时调用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{if(error){NSLog(@"改变通知状态");}
}//16、发现外设的特征的描述数组
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{// 在此处读取描述即可for (CBDescriptor *descriptor in characteristic.descriptors) {self.mDescriptor = descriptor;NSLog(@"发现外设的特征descriptor==%@",descriptor);}
}

7。写入数据以及写入失败成功回调(写入数据时候的特征一定要是可写的特征,这个上一步那里可以知道)

//17、发送数据
- (void)send{// 核心代码在这里[self.mPeripheral writeValue:[@"写数据" dataUsingEncoding:NSUTF8StringEncoding]// 写入的数据forCharacteristic:self.mCharacteristic // 写给哪个特征(这个特征必须是可写特征才能写入成功,因为一个蓝牙外设可以有很多个服务,很多特征)type:CBCharacteristicWriteWithResponse];// 通过此响应记录是否成功写入
}//向peripheral中写入数据后的回调函数
- (void)peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{if (error) {NSLog(@"写入失败%@",error);return;}NSLog(@"write value success(写入成功) : %@===%@", characteristic,[[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]);
}

到此,中心设备相关实现就完成了,如果是跟蓝牙硬件交互,只需要跟硬件相关人员协调写入数据和读取数据的各种格式,以及写入哪个特征等等即可

以下是外部设备相关实现,也就是如果把手机作为外设时候的代码实现

1.定义外设,初始化外设相关名称,代码

@interface NoticePeripheraManagerViewController ()<CBPeripheralManagerDelegate>
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) UILabel *statusL;
@property (strong, nonatomic) NSData                    *dataToSend;
@property (nonatomic, strong) CBMutableCharacteristic *cumCharacteristic;
@end- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor whiteColor];self.statusL = [[UILabel alloc] initWithFrame:self.view.bounds];self.statusL.textColor = [UIColor blackColor];self.statusL.font = [UIFont systemFontOfSize:18];self.statusL.numberOfLines = 0;[self.view addSubview:self.statusL];/*和CBCentralManager类似,蓝牙设备打开需要一定时间,打开成功后会进入委托方法- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;模拟器永远也不会得CBPeripheralManagerStatePoweredOn状态*/self.peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];// 初始化数据self.dataToSend = [@"snadjfkhaw加大困难的是咖啡euijferlfmn ksxncjxznvjeajfrnjadnfjasfndsafnjsadkfnjsa" dataUsingEncoding:NSUTF8StringEncoding];
}
//peripheralManager状态改变
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{switch (peripheral.state) {//在这里判断蓝牙设别的状态  当开启了则可调用  setUp方法(自定义)case CBManagerStatePoweredOn:NSLog(@"powered on");self.statusL.text = [NSString stringWithFormat:@"设备名%@已经打开,可以使用center进行连接",@"ios设备"];[self setUp];break;case CBManagerStatePoweredOff:NSLog(@"powered off");self.statusL.text = @"powered off";break;default:break;}
}- (void)setUp{/*typedef NS_OPTIONS(NSUInteger, CBAttributePermissions) {CBAttributePermissionsReadable                  = 0x01,         //可读CBAttributePermissionsWriteable                 = 0x02,         //可写CBAttributePermissionsReadEncryptionRequired    = 0x04,                 //可读,需要建立安全连接CBAttributePermissionsWriteEncryptionRequired   = 0x08             // //可写,需要建立安全连接} NS_ENUM_AVAILABLE(10_9, 6_0);*/CBMutableCharacteristic *writeReadCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"FF01"] properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite  value:nil permissions:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite];CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"FF66"] primary:YES];[service setCharacteristics:@[writeReadCharacteristic]];self.cumCharacteristic = writeReadCharacteristic;[self.peripheralManager addService:service];}//添加了服务回调
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{NSLog(@"添加服务成功开始广播");[self.peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:@"FF66"]],CBAdvertisementDataLocalNameKey:@"ios设备"}];
}//当中央端连接上了此设备并订阅了特征时会回调 didSubscribeToCharacteristic:
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {NSLog(@"当中央端连接上了此设备并订阅了特征时会回调");[self.peripheralManager updateValue:[@"订阅特征" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic onSubscribedCentrals:nil];
}//当接收到中央端读的请求时会调用didReceiveReadRequest:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {if (request.characteristic.properties & CBCharacteristicPropertyRead) {NSData *data = [@"收到读的请求" dataUsingEncoding:NSUTF8StringEncoding];self.statusL.text = @"收到读的请求";[request setValue:data];[self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];} else {[self.peripheralManager respondToRequest:request withResult:CBATTErrorReadNotPermitted];}
}- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{self.statusL.text = @"收到写的请求";NSData *res= [[NSString stringWithFormat:@"Hello"] dataUsingEncoding:NSUTF8StringEncoding];[self.peripheralManager updateValue:resforCharacteristic:self.cumCharacteristiconSubscribedCentrals:nil];
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/78263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

付费进群搭建二维码

如今&#xff0c;在互联网时代&#xff0c;群组聊天已经成为人们高效沟通和合作的重要方式。然而&#xff0c;对于一些专业团队或机构来说&#xff0c;免费的系统可能无法满足他们对安全性、稳定性和个性化功能的要求。因此&#xff0c;他们需要寻找付费的群组系统&#xff0c;…

如何将安防视频监控系统/视频云存储EasyCVR平台推流到公网直播间?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

基于PyTorch使用LSTM实现新闻文本分类任务

本文参考 PyTorch深度学习项目实战100例 https://weibaohang.blog.csdn.net/article/details/127154284?spm1001.2014.3001.5501 文章目录 本文参考任务介绍做数据的导入 环境介绍导入必要的包介绍torchnet和keras做数据的导入给必要的参数命名加载文本数据数据前处理模型训…

防火墙概述及实战

目录 前言 一、概述 &#xff08;一&#xff09;、防火墙分类 &#xff08;二&#xff09;、防火墙性能 &#xff08;三&#xff09;、iptables &#xff08;四&#xff09;、iptables中表的概念 二、iptables规则匹配条件分类 &#xff08;一&#xff09;、基本匹配条…

echarts常用参数详解汇总(饼图,柱形图,折线图)持续更新中

常用配置&#xff1a; X/Y轴线的基础设置《通用》 细微的差距只能去官网查看了&#xff0c;基本一致 这里只是做了个汇总方便查看 xAxis/yAxis: {show:false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字axisTick:{// 不显示坐标轴刻度线show:false, alignWithLabel: tru…

sklearn中的数据集使用

导库 from sklearn.datasets import load_iris 实现 # 加载数据集 iris load_iris() print(f查看数据集&#xff1a;{iris}) print(f查看数据集的特征&#xff1a;{iris.feature_names}) print(f查看数据集的标签&#xff1a;{iris.target_names}) print(f查看数据集的描述…

看板管理:以可视化方式确定任务优先级

确定工作的优先级是我们今天都要面对的挑战。若处理不当&#xff0c;我们就可能试图一心多用&#xff0c;从而严重损害工作效率。 使用看板方法来设定工作优先级是一种非常直观、快速的方法。 确定工作优先级的看板方法 看板工作流程管理方法的核心在于工作可视化。工作被划…

linux学习总结

shell 1.在文本环境下&#xff0c;shell作为命令解释器&#xff0c;建立了用户和操作系统之间的接口。当用户键入一个命令时&#xff0c;shell将对该命令进行解释&#xff0c;并调用相应的程序。2.Linux下有多个shell&#xff0c;最常用的3个shell: bash tcsh zsh3.shell …

hive3升级

文章目录 一、hive2升级到hive3步骤1.备份hive2元数据库2.导入到hive3对应的hive元数据表3.更新hive_metastore数据表信息3.1需要新增的表3.2需要更新字段的表3.3需要更改数据的表 4.hive3上集群需要的操作4.1更改元数据对应的库名4.2重启HiveMetaStore对应服务 二、hive3新特性…

Elasticsearch:什么是生成式人工智能?

生成式人工智能定义 给学生的解释&#xff08;基本&#xff09;&#xff1a; 生成式人工智能是一种可以创造新的原创内容的技术&#xff0c;例如艺术、音乐、软件代码和写作。 当用户输入提示时&#xff0c;人工智能会根据从互联网上现有示例中学到的知识生成响应&#xff0c;…

记录vite下使用require报错和解决办法

前情提要 我们现在项目用的是vite4react18开发的项目、但是最近公司有个睿智的人让我把webpack中的bpmn组件迁移过来、结果就出现问题啦&#xff1a;因为webpack是commonjs规范、但是vite不是、好像是es吧、可想而知各种报错 废话不多说啦 直接上代码&#xff1a; 注释是之前c…

【Spring】手动实现Spring底层机制-问题的引出

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理手动实现Spring底层机制-问题的引出 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一下&#x1…

工厂设计模式

github&#xff1a;GitHub - QiuliangLee/pattern: 设计模式 概念 根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式&#xff0c;根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。 简单工厂模式、工厂方法模式和抽象工厂模式有何区别&#xff1f; - 知…

一点整理

&#xff08;1&#xff09; 美国在2010年以后开始流行数字化转型的。 在2010年以前&#xff0c; 2006年社交网络FB “YOU”&#xff1a;在2004-2006 Web2.0热之前&#xff0c;企业是无法直接触达到每个消费者的2006年Amazon电子商务&#xff1a;这个是我瞎凑的&#xff0c;但因…

运算放大器学习笔记

目录 一、基本定理二、基本定义三、负反馈电路四、同向放大电路五、反向放大电路六、差分放大电路 一、基本定理 【电路示意图】 开环放大公式 VOAvo(V-V-) 开环放大倍数&#xff08;增益&#xff09;非常大&#xff0c;105 或 106 输入阻抗超级大&#xff08;可以理解为电…

Spring Boot自动装配原理

简介 Spring Boot是一个开源的Java框架&#xff0c;旨在简化Spring应用程序的搭建和开发。它通过自动装配的机制&#xff0c;大大减少了繁琐的配置工作&#xff0c;提高了开发效率。本文将深入探讨Spring Boot的自动装配原理。 自动装配的概述 在传统的Spring框架中&#xf…

八股文学习一(存储)

一. 存储 行式存储的原理与特点 对于 OLAP 场景&#xff0c;大多都是对一整行记录进行增删改查操作的&#xff0c;那么行式存储采用以行的行式在磁盘上存储数据就是一个不错的选择。 当查询基于需求字段查询和返回结果时&#xff0c;由于这些字段都埋藏在各行数据中&#xf…

AcWing 5147. 数量 + 5148. 字符串匹配 - 思维+字符串处理

5147. 数量 这个题是之前某场周赛第三题的中间一个步骤 这里我选择使用递归&#xff0c;因为数据范围是1e9&#xff0c;所以当传入的数字位数超过9为时&#xff0c;即可终止递归。这里只需要传入一个参数dep来表示当前数字有多少位就可以。 但是在这之前&#xff0c;我并没有传…

【Node】Mac多版本Node切换

1、查看当前电脑是否安装node node -v或者查看当前电脑通过brew安装的node路径 ls /usr/local/Cellar/node*2、查看可安装的node brew search node3、安装其他版本node 下载需要安装的node版本 brew install node144、brew切换node版本 假设之前的版本是18&#xff0c;需…

Uniapp学习之从零开始写一个简单的小程序demo(新建页面,通过导航切换页面,发送请求)

先把官网文档摆在这&#xff0c;后面会用到的 [uniapp官网文档]: https://uniapp.dcloud.net.cn/vernacular.html# 一、开发工具准备 1-1 安装HBuilder 按照官方推荐&#xff0c;先装一个HBuilder 下载地址&#xff1a; https://www.dcloud.io/hbuilderx.html1-2 安装微信开…