iOS基于CoreBlutooth的蓝牙开发
来源:互联网 发布:ubuntu如何安装福昕 编辑:程序博客网 时间:2024/05/18 03:45
首先如同网络一般,蓝牙也类似的可以分服务端和客户端,CoreBlutooth中有两个角色,一个是Peripheral,相当于服务器端,也就是我们打开手机蓝牙搜索时找到的各个设备;一个是Central,相当于客户端,也就是我们使用的手机,这两个角色和一般的手机使用主权引起的角色意识有点冲突。
蓝牙通信过程中有几个部分,一个是Service,即服务器提供的服务,一个服务端可能有一个或者多个Service,还有一个是Characteristic,即特征值,相当于沟通过程中的字段,服务端和客户端可以针对指定特征值进行数据交流。
因为没有蓝牙模块和蓝牙设备,所以我是在MAC端编写了Peripheral端,手机上运行Central端(蓝牙程序必须真机调试)
Peripheral端
#import <CoreBluetooth/CoreBluetooth.h>#define TRANSFER_SERVICE_UUID @"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"//服务的UUID#define TRANSFER_CHARACTERISTIC_UUID @"1bd51666-e7cb-469b-8e4d-2742f1ba77dd"//读取端口的特征值UUID#define TRANSFER_CHARACTERISTIC1_UUID @"2bd51666-e7cb-469b-8e4d-2742f1ba77dd"//写入端口的特征值UUID@interface ViewController ()<CBPeripheralManagerDelegate>@property (nonatomic,strong) CBPeripheralManager *peripheral;//peripheral管理者@property (nonatomic,strong) CBMutableCharacteristic *transferCharacteristic;//读取端口特征值@property (nonatomic,strong) CBMutableCharacteristic *transferCharacteristic1;//写入端口特征值@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //按钮 用于更新字段值 NSButton *button = [NSButton buttonWithTitle:@"dianji" target:self action:@selector(btnClick)]; button.frame = NSRectFromCGRect(CGRectMake(10, 10, 100, 50)); [self.view addSubview:button]; self.peripheral = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];//初始化,并设置代理 CBMutableService *transferService = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];//构建服务 // 构建两个特征值 参数Type:特征值UUID,properties:端口属性,通知、读、写、不带回应写入等等,value:特征值,如果要设置,特征值须为readonly,permissions:读写权限 self.transferCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] properties: CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable]; // properties很重要,如果没有设置读属性,central调用read方法时会被禁止 self.transferCharacteristic1 = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC1_UUID] properties: CBCharacteristicPropertyNotify | CBCharacteristicPropertyWrite | CBCharacteristicPropertyWriteWithoutResponse value:nil permissions: CBAttributePermissionsReadEncryptionRequired | CBAttributePermissionsWriteEncryptionRequired]; // 为服务添加特征值 transferService.characteristics = @[self.transferCharacteristic,self.transferCharacteristic1]; [self.peripheral addService:transferService];//为peripheral添加服务 [self.peripheral startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]}]; //开启广播}// 必须的代理,状态更新- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{ NSLog(@"%ld",(long)peripheral.state);}// 接收到写入请求后的代理- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests{ CBATTRequest *request = requests[0]; NSLog(@"-----%d",[self.peripheral updateValue:request.value forCharacteristic:self.transferCharacteristic1 onSubscribedCentrals:nil]);}// 接收到读取请求后的代理- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{ NSLog(@"read");}- (void)btnClick{ // [self.peripheral updateValue:[NSData dataWithBytes:"Hello world" length:11] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; // self.transferCharacteristic.value = [NSData dataWithBytes:"Hello World" length:11]; [self.peripheral updateValue:[NSData dataWithBytes:"hello World" length:11] forCharacteristic:self.transferCharacteristic1 onSubscribedCentrals:nil];//更新指定特征值端口的值,并不会改变characteristic.value [self.peripheral updateValue:[NSData dataWithBytes:"hello" length:11] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; NSLog(@"%@",[[NSString alloc]initWithData:self.transferCharacteristic1.value encoding:NSUTF8StringEncoding]); }- (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded.}@end
上面是服务端的代码,需要注意的是如果是自己开发蓝牙模块的话,相关service的UUID以及characteristic的UUID可以和模块开发人员商定,如果是手环或者其他商用成品的话,商家应该会提供相关UUID。
Central端
//// ViewController.m// testDD//// Created by 周小伟 on 2017/7/7.// Copyright © 2017年 周小伟. All rights reserved.//#import "ViewController.h"#import <CoreBluetooth/CoreBluetooth.h>// 三个特征值必须和服务端一样,不然找不到指定特征值#define TRANSFER_SERVICE_UUID @"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"#define TRANSFER_CHARACTERISTIC_UUID @"1bd51666-e7cb-469b-8e4d-2742f1ba77dd"#define TRANSFER_CHARACTERISTIC1_UUID @"2bd51666-e7cb-469b-8e4d-2742f1ba77dd"@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>@property (nonatomic,strong) NSMutableArray *peripherArr;//用于存储已经发现的设备@property (nonatomic,strong) CBCentralManager *manager;//central管理者@property (nonatomic,strong) CBPeripheral *peripheral;//当前连接的peripheral@property (nonatomic,strong) CBCharacteristic *char1;//读取的特征值端口@property (nonatomic,strong) CBCharacteristic *char2;//写入的特征值端口@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; self.manager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];//初始化管理者 //CBCentralManager非当前循环创建,如果不用强指针引用,出了应用域就会被释放,运行会报错}// central管理者代理,必须调用 判断蓝牙状态,如果状态为蓝牙打开的话,开始扫描- (void)centralManagerDidUpdateState:(CBCentralManager *)central{ if (central.state == CBManagerStatePoweredOn) { [self.manager scanForPeripheralsWithServices:nil options:nil]; }}// 扫描的代理方法 在停止扫描之前会不断调用- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{ if (!peripheral.name) { return;//过滤没有名字的设备 } [self.manager stopScan];//停止扫描,也可以在连接设备后停止扫描 //因为附近只有一个设备,所以没有对设备进行判断,实际上可以添加到数组中保存,顺便添加强引用 [central connectPeripheral:peripheral options:nil];//连接设备,如果有必要可以针对设备属性进行判断,然后连接,比如设备名字,UUID等 self.peripheral = peripheral;//只为了添加强引用,一般不这么写 self.peripheral.delegate = self;//设置代理}//管理者代理,连接到设备后调用- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];//查找服务,参数如果设置为nil为查找所有服务}//peripheral代理,发现没用的服务时调用- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices{ NSLog(@"---- %@",invalidatedServices);}//发现服务后调用- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{ NSArray *services = peripheral.services; //获取设备的所有服务,下面的处理只因为服务端我只有一个service,所以没有进行处理,实际上一个设备会有多个service,需要遍历分别处置 if (services.count) { CBService *service = services[0]; CBUUID *writeUUID = [CBUUID UUIDWithString: TRANSFER_CHARACTERISTIC1_UUID]; CBUUID *readUUID = [CBUUID UUIDWithString: TRANSFER_CHARACTERISTIC_UUID]; [peripheral discoverCharacteristics:@[writeUUID, readUUID] forService:service];//查找指定特征值 }}//peripheral代理,发现特征值时调用- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ if (!error) { NSArray *characteristicArray = service.characteristics;//获取service的特征值,实际上一个service可能有多个特征值,需要自己处理,比如针对特征值的properties进行处理 if(characteristicArray.count > 1){ //因为读写操作是针对特征值进行的,所以要取得两个特征值 CBCharacteristic *readCharacteristic = characteristicArray[0]; CBCharacteristic *writeCharacteristic = characteristicArray[1]; self.char1 = readCharacteristic; self.char2 = writeCharacteristic; // 通知使能, `YES` enable notification only, `NO` disable notifications and indications //[peripheral setNotifyValue:YES forCharacteristic:readCharacteristic]; // [peripheral setNotifyValue:YES forCharacteristic:writeCharacteristic]; //为指定特征值添加通知,需要特征值的properties设置了notify属性才能设置,一般前面会加入判断 if(writeCharacteristic.properties & CBCharacteristicPropertyNotify) // [peripheral readValueForCharacteristic:readCharacteristic];//读取数据,需要特征值的properties设置了read属性,判断方法类似上一句// [peripheral readValueForCharacteristic:writeCharacteristic]; } NSLog(@"Hello "); } else { NSLog(@"Discover Charactertics Error : %@", error); }}// peripheral代理,设置过notify属性的特征值的值发生变化后会调用这个方法,比如我的demo里面的写入特征值我设置了notify和write,然后写入后因为值改变了就会调用这个代理方法,在peripheral为特征值设置setNotifyValue:forCharacteristic:时就会调用这个方法- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ if (error) { NSLog(@"%@",characteristic); NSLog(@"%@",error.userInfo); return; } CBCharacteristicProperties properties = characteristic.properties; if (properties) { NSLog(@"%@",characteristic.value); }}// peripheral代理方法,写入操作后调用需要写入时设置type为withResponse才会调用- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ if (!error) { NSLog(@"Write Success"); }else{ NSLog(@"WriteValue Error = %@",error.userInfo); }}// peripheral代理方法,指定特征值的value值变化了后调用- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ if (error) { NSLog(@"update value error:%@",error.userInfo); }else{ NSData *responseData = characteristic.value; NSLog(@"||||||||||%@",[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding]); NSLog(@"%@",[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]); }}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ static int i = 0; NSString *str = [NSString stringWithFormat:@"Hello %d",i]; [self.peripheral writeValue:[NSData dataWithBytes:str.UTF8String length:strlen(str.UTF8String)]forCharacteristic:self.char2 type:CBCharacteristicWriteWithResponse];//写入操作,参数type,必须要withResponse才会有代理回调,如果要设置withoutResponse需要相关特征值设置了一样的属性 NSLog(@"%ld",[self.peripheral maximumWriteValueLengthForType:CBCharacteristicWriteWithoutResponse]); i++; // [self.peripheral readValueForCharacteristic:self.char1];//读取操作}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}@end
主要的蓝牙交互过程就类似于上面所示,但实际上沟通过程并没有达到理想效果,比如写入操作只能进行一次,我并不知道是否因为设备的原因,如果有机会可以找到其他设备再来尝试。
阅读全文
0 0
- iOS基于CoreBlutooth的蓝牙开发
- IOS 有关蓝牙的开发
- iOS蓝牙的开发专题
- ios 基于GameKit框架的蓝牙通信
- iOS 蓝牙开发BLE4.0的资料收集,基于原生Core Bluetooth
- 基于JSR82的蓝牙应用开发手记
- android中基于蓝牙开发的demo
- 基于android系统的蓝牙开发总结
- ios 蓝牙开发,蓝牙应用
- IOS Objective-c 蓝牙开发教程一蓝牙的连接
- iOS 关于蓝牙开发的相关知识
- iOS 关于蓝牙开发的相关知识
- iOS开发--核心蓝牙的使用
- iOS开发 - 蓝牙学习的总结
- ios -蓝牙开发
- ios蓝牙开发
- IOS 蓝牙开发
- iOS 蓝牙开发备忘
- apache设置中文支持&长文件名显示
- Android测试工具之强大的adb工具
- nginx配置详细-最全说明
- JS获取鼠标的坐标和滚动条的位置
- 排序:冒泡排序(算法)
- iOS基于CoreBlutooth的蓝牙开发
- hbsolr编译和bigtomcat编译
- 第一篇博客
- win7 计划任务 XCOPY命令使用
- opencv学习笔记--Laplace算子
- SpringBoot-Websocket
- BeautifulSoup学习笔记1
- 同一元素上,通过v-on绑定多个相同事件的函数
- kotlin 的配置及使用