iOS蓝牙开发

iOS蓝牙开发CoreBluetoot 详解 CoreBluetoot 框架的核心其实是两个东西 peripheral 和 central 可以理解成外设和中心 图中两组 api 分别对应不同的业务场景 左侧叫做中心模式 就是以你的 app 作为中心 连接其他的外设的场景 而右侧称为外设模式 使用手机作为外设别其他中心设备操作的场景关于蓝牙开发的一些重要的理论概念 1 服务 services 蓝牙外设对外广播的

CoreBluetooth详解

CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。

图中两组api分别对应不同的业务场景,左侧叫做中心模式,就是以你的app作为中心,连接其他的外设的场景,而右侧称为外设模式,使用手机作为外设别其他中心设备操作的场景

image

关于蓝牙开发的一些重要的理论概念:

CBCentralMannager 中心模式

以手机(app)作为中心,连接其他外设的场景。详细流程如下:

步骤1.建立一个Central Manager实例进行蓝牙管理

步骤2.搜索外围设备

步骤3.连接外围设备

步骤4.获得外围设备的服务

步骤5.获得服务的特征

步奏6.从外围设备读数据(直接读取和订阅两种方法)

步骤7.给外围设备发送数据

#import "ViewController.h" #import #define kPeripheralName @"Kenshin Cui's Device" //外围设备名称 #define kServiceUUID @"C4FB2349-72FE-4CA2-94D6-1F3CB16331EE" //服务的UUID #define kCharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5EFC" //特征的UUID @interface ViewController () @property (strong,nonatomic) CBPeripheralManager *peripheralManager;//外围设备管理器 @property (strong,nonatomic) NSMutableArray *centralM;//订阅此外围设备特征的中心设备 @property (strong,nonatomic) CBMutableCharacteristic *characteristicM;//特征 @property (weak, nonatomic) IBOutlet UITextView *log; //日志记录 @end 
@implementation ViewController #pragma mark - 控制器视图事件 - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark - UI事件 - (IBAction)startClick:(UIBarButtonItem *)sender { //创建中心设备管理器并设置当前控制器视图为代理 _centralManager=[[CBCentralManager alloc]initWithDelegate:self queue:nil]; } #pragma mark - CBCentralManager代理方法 //中心服务器状态更新后 -(void)centralManagerDidUpdateState:(CBCentralManager *)central{ switch (central.state) { case CBPeripheralManagerStatePoweredOn: NSLog(@"BLE已打开."); [self writeToLog:@"BLE已打开."]; //扫描外围设备 // [central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}]; [central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}]; break; default: NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."); [self writeToLog:@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."]; break; } } / * 发现外围设备 * * @param central 中心设备 * @param peripheral 外围设备 * @param advertisementData 特征数据 * @param RSSI 信号质量(信号强度) */ -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ NSLog(@"发现外围设备..."); [self writeToLog:@"发现外围设备..."]; //停止扫描 [self.centralManager stopScan]; //连接外围设备 if (peripheral) { //添加保存外围设备,注意如果这里不保存外围设备(或者说peripheral没有一个强引用,无法到达连接成功(或失败)的代理方法,因为在此方法调用完就会被销毁 if(![self.peripherals containsObject:peripheral]){ [self.peripherals addObject:peripheral]; } NSLog(@"开始连接外围设备..."); [self writeToLog:@"开始连接外围设备..."]; [self.centralManager connectPeripheral:peripheral options:nil]; } } //连接到外围设备 -(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ NSLog(@"连接外围设备成功!"); [self writeToLog:@"连接外围设备成功!"]; //设置外围设备的代理为当前视图控制器 peripheral.delegate=self; //外围设备开始寻找服务 [peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]]; } //连接外围设备失败 -(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ NSLog(@"连接外围设备失败!"); [self writeToLog:@"连接外围设备失败!"]; } #pragma mark - CBPeripheral 代理方法 //外围设备寻找到服务后 -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{ NSLog(@"已发现可用服务..."); [self writeToLog:@"已发现可用服务..."]; if(error){ NSLog(@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription); [self writeToLog:[NSString stringWithFormat:@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription]]; } //遍历查找到的服务 CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID]; CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID]; for (CBService *service in peripheral.services) { if([service.UUID isEqual:serviceUUID]){ //外围设备查找指定服务中的特征 [peripheral discoverCharacteristics:@[characteristicUUID] forService:service]; } } } //外围设备寻找到特征后 -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ NSLog(@"已发现可用特征..."); [self writeToLog:@"已发现可用特征..."]; if (error) { NSLog(@"外围设备寻找特征过程中发生错误,错误信息:%@",error.localizedDescription); [self writeToLog:[NSString stringWithFormat:@"外围设备寻找特征过程中发生错误,错误信息:%@",error.localizedDescription]]; } //遍历服务中的特征 CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID]; CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID]; if ([service.UUID isEqual:serviceUUID]) { for (CBCharacteristic *characteristic in service.characteristics) { if ([characteristic.UUID isEqual:characteristicUUID]) { //情景一:通知 /*找到特征后设置外围设备为已通知状态(订阅特征): *1.调用此方法会触发代理方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error *2.调用此方法会触发外围设备的订阅代理方法 */ [peripheral setNotifyValue:YES forCharacteristic:characteristic]; //情景二:读取 // [peripheral readValueForCharacteristic:characteristic]; // if(characteristic.value){ // NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]; // NSLog(@"读取到特征值:%@",value); // } } } } } //特征值被更新后 -(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ NSLog(@"收到特征更新通知..."); [self writeToLog:@"收到特征更新通知..."]; if (error) { NSLog(@"更新通知状态时发生错误,错误信息:%@",error.localizedDescription); } //给特征值设置新的值 CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID]; if ([characteristic.UUID isEqual:characteristicUUID]) { if (characteristic.isNotifying) { if (characteristic.properties==CBCharacteristicPropertyNotify) { NSLog(@"已订阅特征通知."); [self writeToLog:@"已订阅特征通知."]; return; }else if (characteristic.properties ==CBCharacteristicPropertyRead) { //从外围设备读取新值,调用此方法会触发代理方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error [peripheral readValueForCharacteristic:characteristic]; } }else{ NSLog(@"停止已停止."); [self writeToLog:@"停止已停止."]; //取消连接 [self.centralManager cancelPeripheralConnection:peripheral]; } } } //更新特征值后(调用readValueForCharacteristic:方法或者外围设备在订阅后更新特征值都会调用此代理方法) -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ if (error) { NSLog(@"更新特征值时发生错误,错误信息:%@",error.localizedDescription); [self writeToLog:[NSString stringWithFormat:@"更新特征值时发生错误,错误信息:%@",error.localizedDescription]]; return; } if (characteristic.value) { NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]; NSLog(@"读取到特征值:%@",value); [self writeToLog:[NSString stringWithFormat:@"读取到特征值:%@",value]]; }else{ NSLog(@"未发现特征值."); [self writeToLog:@"未发现特征值."]; } } #pragma mark - 属性 -(NSMutableArray *)peripherals{ if(!_peripherals){ _peripherals=[NSMutableArray array]; } return _peripherals; } #pragma mark - 私有方法 / * 记录日志 * * @param info 日志信息 */ -(void)writeToLog:(NSString *)info{ self.log.text=[NSString stringWithFormat:@"%@\r\n%@",self.log.text,info]; } @end 

CBPeripheralManager 外设模式

#import "ViewController.h" #import #define kServiceUUID @"C4FB2349-72FE-4CA2-94D6-1F3CB16331EE" //服务的UUID #define kCharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5EFC" //特征的UUID @interface ViewController () @property (strong,nonatomic) CBCentralManager *centralManager;//中心设备管理器 @property (strong,nonatomic) NSMutableArray *peripherals;//连接的外围设备 @property (weak, nonatomic) IBOutlet UITextView *log;//日志记录 @end 
@implementation ViewController #pragma mark - 视图控制器方法 - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark - UI事件 //创建外围设备 - (IBAction)startClick:(UIBarButtonItem *)sender { _peripheralManager=[[CBPeripheralManager alloc]initWithDelegate:self queue:nil]; } //更新数据 - (IBAction)transferClick:(UIBarButtonItem *)sender { [self updateCharacteristicValue]; } #pragma mark - CBPeripheralManager代理方法 //外围设备状态发生变化后调用 -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{ switch (peripheral.state) { case CBPeripheralManagerStatePoweredOn: NSLog(@"BLE已打开."); [self writeToLog:@"BLE已打开."]; //添加服务 [self setupService]; break; default: NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."); [self writeToLog:@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."]; break; } } //外围设备添加服务后调用 -(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{ if (error) { NSLog(@"向外围设备添加服务失败,错误详情:%@",error.localizedDescription); [self writeToLog:[NSString stringWithFormat:@"向外围设备添加服务失败,错误详情:%@",error.localizedDescription]]; return; } //添加服务后开始广播 NSDictionary *dic=@{CBAdvertisementDataLocalNameKey:kPeripheralName};//广播设置 [self.peripheralManager startAdvertising:dic];//开始广播 NSLog(@"向外围设备添加了服务并开始广播..."); [self writeToLog:@"向外围设备添加了服务并开始广播..."]; } -(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{ if (error) { NSLog(@"启动广播过程中发生错误,错误信息:%@",error.localizedDescription); [self writeToLog:[NSString stringWithFormat:@"启动广播过程中发生错误,错误信息:%@",error.localizedDescription]]; return; } NSLog(@"启动广播..."); [self writeToLog:@"启动广播..."]; } //订阅特征 -(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{ NSLog(@"中心设备:%@ 已订阅特征:%@.",central,characteristic); [self writeToLog:[NSString stringWithFormat:@"中心设备:%@ 已订阅特征:%@.",central.identifier.UUIDString,characteristic.UUID]]; //发现中心设备并存储 if (![self.centralM containsObject:central]) { [self.centralM addObject:central]; } /*中心设备订阅成功后外围设备可以更新特征值发送到中心设备,一旦更新特征值将会触发中心设备的代理方法: -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error */ // [self updateCharacteristicValue]; } //取消订阅特征 -(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{ NSLog(@"didUnsubscribeFromCharacteristic"); } -(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(CBATTRequest *)request{ NSLog(@"didReceiveWriteRequests"); } -(void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict{ NSLog(@"willRestoreState"); } #pragma mark -属性 -(NSMutableArray *)centralM{ if (!_centralM) { _centralM=[NSMutableArray array]; } return _centralM; } #pragma mark - 私有方法 //创建特征、服务并添加服务到外围设备 -(void)setupService{ /*1.创建特征*/ //创建特征的UUID对象 CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID]; //特征值 // NSString *valueStr=kPeripheralName; // NSData *value=[valueStr dataUsingEncoding:NSUTF8StringEncoding]; //创建特征 / 参数 * uuid:特征标识 * properties:特征的属性,例如:可通知、可写、可读等 * value:特征值 * permissions:特征的权限 */ CBMutableCharacteristic *characteristicM=[[CBMutableCharacteristic alloc]initWithType:characteristicUUID properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable]; self.characteristicM=characteristicM; // CBMutableCharacteristic *characteristicM=[[CBMutableCharacteristic alloc]initWithType:characteristicUUID properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable]; // characteristicM.value=value; /*创建服务并且设置特征*/ //创建服务UUID对象 CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID]; //创建服务 CBMutableService *serviceM=[[CBMutableService alloc]initWithType:serviceUUID primary:YES]; //设置服务的特征 [serviceM setCharacteristics:@[characteristicM]]; /*将服务添加到外围设备*/ [self.peripheralManager addService:serviceM]; } //更新特征值 -(void)updateCharacteristicValue{ //特征值 NSString *valueStr=[NSString stringWithFormat:@"%@ --%@",kPeripheralName,[NSDate date]]; NSData *value=[valueStr dataUsingEncoding:NSUTF8StringEncoding]; //更新特征值 [self.peripheralManager updateValue:value forCharacteristic:self.characteristicM onSubscribedCentrals:nil]; [self writeToLog:[NSString stringWithFormat:@"更新特征值:%@",valueStr]]; } / * 记录日志 * * @param info 日志信息 */ -(void)writeToLog:(NSString *)info{ self.log.text=[NSString stringWithFormat:@"%@\r\n%@",self.log.text,info]; } @end 

蓝牙连接发送数据的流程图

16a2962d7ce67281.png

lightblue怎么用

OTA(空中升级)

将手机作为外围设备开发

iOS浅析蓝牙设备之服务器(外围设备)

APP被作为外设

遇到的坑

截屏2019-10-2315.57.54.png

 [self.centralManager scanForPeripheralsWithServices:nil options:nil]; 

一般蓝牙连接失败我们会实现以下方法

// 连接失败(但不包含超时,系统没有超时处理) - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { if (error && self.delegate && [self.delegate respondsToSelector:@selector(centralTool:connectFailure:)]) { [self.delegate centralTool:self connectFailure:error]; } } - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { [self autoConnect]; } 

但是当广播设备的蓝牙断开再想重连的话还要实现下面这个方法

- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray 
  
    *)invalidatedServices{ [self.centralManager connectPeripheral:peripheral options:nil]; // 注意保留 Peripheral 的引用 self.lastConnectedPeripheral = peripheral; [self startTimer]; } 
  

只有这样才能实现断开蓝牙重开蓝牙秒连

另外,有时候要提高搜索效率的话,可以过滤蓝牙的名字

 NSString *name = peripheral.name; if (name.length == 0) { return; } NSLog(@"name === %@",name); NSString *string = [NSString stringWithFormat:@"已发现 peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.identifier, advertisementData]; NSLog(@"string == %@",string); if ([name rangeOfString:@"Berry"].location == NSNotFound) { return; } // NSString *kCBAdvDataLocalName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; // if ([kCBAdvDataLocalName rangeOfString:@"Berry"].location == NSNotFound) { // return; // } 
//添加服务后开始广播 //广播设置 NSDictionary *dic=@{CBAdvertisementDataLocalNameKey:MyDeviceName,CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:@"FFE0"]]}; //广播设置 [self.peripheralManager startAdvertising:dic];//开始广播 

不过,如果这块都设置了,对于快速精准找到目标蓝牙服务是大有裨益的,也会减少耗电量,提高响应速度等等。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214392.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午4:22
下一篇 2026年3月18日 下午4:23


相关推荐

  • 倒立摆matlab仿真程序_倒立摆状态空间建模

    倒立摆matlab仿真程序_倒立摆状态空间建模Matlab程序设计上交作业要求1纸质文档设计分析报告一份包括系统建模、系统分析、系统设计思路、程序及其执行结果。2Matlab程序按班级统一上交后备查。题目一考虑如图所示的倒立摆系统。图中倒立摆安装在一个小车上。这里仅考虑倒立摆在图面内运动的二维问题。图倒立摆系统假定倒立摆系统的参数如下。摆杆的质量m=0.1g摆杆的长度2l=1m小车的质量M=1kg重力加速度g=10…

    2022年8月18日
    8
  • oracle隐式转换和显式转换_oracle显示游标和隐式

    oracle隐式转换和显式转换_oracle显示游标和隐式和其他的关系型数据库一样,oracle中也能进行一些隐式的数据转换,这对我们写SQL语句有非常用,我们可以不必麻烦地手动转化很多类型的字符。虽然前面我们介绍了一些使用例如to_char,to_date的函数进行强制转换的方法,但是隐式转换也还是不错的。Orac和其他的关系型数据库一样,oracle中也能进行一些隐式的数据转换,这对我们写SQL语句有非常用,我们可以不必麻烦地手动转化很…

    2022年10月11日
    7
  • Fleet问题

    Fleet问题1.  是否能自由部署fleetservices在1台或多台machine上。(可以指定部署1个服务在某台机器上,或者指定某个服务在多台机器上)

    2022年4月26日
    63
  • Prompt, Prompt Engineering, 提示工程, 提示词

    Prompt, Prompt Engineering, 提示工程, 提示词

    2026年3月13日
    2
  • Android UI设计

    Android UI设计UI概述1、在Android应用中,UI(UserInterface)界面是人与手机之间数据传递、交互信息的重要媒介和对话接中。2、Android程序开发最重要的一个环节就是界面处理,界面的美观度直接影响用户的第一印象,因此,开发一个整齐、美观的界面是至关重要的。3、Android应用的界面是由View和ViewGroup对象构建而成的。View类是Android系统平台上用户界面表示的基本单元,View的一些子类被统称为Widgets(工具),它们提供了诸如文本输入框和按钮之类的UI对象

    2022年6月29日
    29
  • 零基础用 GPT-5 做网页:3 步生成 + 部署上线完整教程

    零基础用 GPT-5 做网页:3 步生成 + 部署上线完整教程

    2026年3月16日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号