最近写一个蓝牙项目 初步实现一下蓝牙设备连接交互,后期继续完善。。。。
1、连接蓝牙相关操作
BlueToothManger.h
// // BlueToothManger.h // SmartRobot // // Created by 杜文杰 on 2017/8/2. // Copyright © 2017年 appleLJ. All rights reserved. // #import <Foundation/Foundation.h> #import <CoreBluetooth/CoreBluetooth.h> @interface BlueToothManger : CBCentralManager // connectSeccuss YES 连接成功 NO 连接失败 @property (nonatomic, copy) void(^cbperipheral)(CBPeripheral *peripheral,BOOL connectSeccuss); @property (nonatomic, copy) void(^cbCharacteristic)(CBCharacteristic *characteristic); - (instancetype)ShareBlueToothManger; - (CBCentralManager *)centralManager; @end
BlueToothManger.m
// // BlueToothManger.m // SmartRobot // // Created by 杜文杰 on 2017/8/2. // Copyright © 2017年 appleLJ. All rights reserved. // #import "BlueToothManger.h" #import <CoreBluetooth/CoreBluetooth.h> @interface BlueToothManger ()<CBCentralManagerDelegate,CBPeripheralDelegate> /// 中央管理者 -->管理设备的扫描 --连接 @property (nonatomic, strong) CBCentralManager *centralManager; // 存储的设备 @property (nonatomic, strong) NSMutableArray *peripherals; // 扫描到的设备 @property (nonatomic, strong) CBPeripheral *cbPeripheral; // 文本 //@property (weak, nonatomic) IBOutlet UITextView *peripheralText; // 蓝牙状态 @property (nonatomic, assign) CBManagerState peripheralState; @property (nonatomic, copy) NSString *sendServerValue; @property (nonatomic, copy) BlueToothManger *blueToothManger; @end // 蓝牙4.0设备名 static NSString * const kBlePeripheralName = @"JDY-08"; // 通知服务 static NSString * const kNotifyServerUUID = @"FFE0"; // 写服务 static NSString * const kWriteServerUUID = @"FFE1"; // 通知特征值 static NSString * const kNotifyCharacteristicUUID = @"FFE1"; // 写特征值 static NSString * const kWriteCharacteristicUUID = @"FFE1"; @implementation BlueToothManger - (instancetype)ShareBlueToothManger { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _blueToothManger = [[BlueToothManger alloc]init]; }); return _blueToothManger; } - (NSMutableArray *)peripherals { if (!_peripherals) { _peripherals = [NSMutableArray array]; } return _peripherals; } - (CBCentralManager *)centralManager { if (!_centralManager) { _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; } return _centralManager; } // 222 扫描设备 - (void)scanForPeripherals { [self.centralManager stopScan]; NSLog(@"扫描设备"); // [self showMessage:@"扫描设备"]; if (self.peripheralState == CBManagerStatePoweredOn) { [self.centralManager scanForPeripheralsWithServices:nil options:nil]; } } // 连接设备 - (void)connectToPeripheral { if (self.cbPeripheral != nil) { NSLog(@"连接设备"); // [self showMessage:@"连接设备"]; [self.centralManager connectPeripheral:self.cbPeripheral options:nil]; } else { // [self showMessage:@"无设备可连接"]; } } // 清空设备 - (void)clearPeripherals { NSLog(@"清空设备"); [self.peripherals removeAllObjects]; // self.peripheralText.text = @""; // [self showMessage:@"清空设备"]; if (self.cbPeripheral != nil) { // 取消连接 NSLog(@"取消连接"); // [self showMessage:@"取消连接"]; [self.centralManager cancelPeripheralConnection:self.cbPeripheral]; } } ////000 //- (void)viewDidLoad { // [super viewDidLoad]; // [self centralManager]; //} ///111 //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态 状态更新时调用 - (void)centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { case CBManagerStateUnknown:{ NSLog(@"为知状态"); self.peripheralState = central.state; } break; case CBManagerStateResetting: { NSLog(@"重置状态"); self.peripheralState = central.state; } break; case CBManagerStateUnsupported: { NSLog(@"不支持的状态"); self.peripheralState = central.state; } break; case CBManagerStateUnauthorized: { NSLog(@"未授权的状态"); self.peripheralState = central.state; } break; case CBManagerStatePoweredOff: { NSLog(@"关闭状态"); self.peripheralState = central.state; } break; case CBManagerStatePoweredOn: { NSLog(@"开启状态-可用状态"); self.peripheralState = central.state; // 链接成功开始扫描设备 [self scanForPeripherals]; NSLog(@"%ld",(long)self.peripheralState); } break; default: break; } } /** 333扫描到设备 发现设备是开启状态后调用方法 @param central 中心管理者 @param peripheral 扫描到的设备 @param advertisementData 广告信息 @param RSSI 信号强度 */ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI { // [self showMessage:[NSString stringWithFormat:@"发现设备,设备名:%@",peripheral.name]]; // 设备数组中是否存在 该设备 if (![self.peripherals containsObject:peripheral]) { [self.peripherals addObject:peripheral]; NSLog(@"%@",peripheral); //最常用的场景是查找某一个前缀开头的设备 mogu if ([peripheral.name hasPrefix:@"JDY"] ) { // [self showMessage:@"开始连接"]; [self.centralManager connectPeripheral:peripheral options:nil]; } } } /** 连接失败 @param central 中心管理者 @param peripheral 连接失败的设备 @param error 错误信息 */ - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { // [self showMessage:@"连接失败"]; if ([peripheral.name isEqualToString:kBlePeripheralName]) { [self.centralManager connectPeripheral:peripheral options:nil]; } } /** 连接断开 @param central 中心管理者 @param peripheral 连接断开的设备 @param error 错误信息 */ - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { // [self showMessage:@"断开连接"]; if ([peripheral.name isEqualToString:kBlePeripheralName]) { [self.centralManager connectPeripheral:peripheral options:nil]; } } /** 444连接成功 @param central 中心管理者 @param peripheral 连接成功的设备 */ - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"连接设备:%@成功",peripheral.name); // self.peripheralText.text = [NSString stringWithFormat:@"连接设备:%@成功",peripheral.name]; // [self showMessage:[NSString stringWithFormat:@"连接设备:%@成功",peripheral.name]]; // 设备 self.cbPeripheral = peripheral; self.cbperipheral(peripheral, YES); // 设置设备的代理 peripheral.delegate = self; // services:传入nil 代表扫描所有服务 [peripheral discoverServices:nil]; } /** 555扫描到服务 @param peripheral 服务对应的设备 @param error 扫描错误信息 */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { // 遍历所有的服务 for (CBService *service in peripheral.services) { NSLog(@"服务:%@",service.UUID.UUIDString); // 获取对应的服务 if ([service.UUID.UUIDString isEqualToString:kWriteServerUUID] || [service.UUID.UUIDString isEqualToString:kNotifyServerUUID]) { // 根据服务去扫描特征 [peripheral discoverCharacteristics:nil forService:service]; } } } /** 666扫描到对应的特征 @param peripheral 设备 @param service 特征对应的服务 @param error 错误信息 */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { // 遍历所有的特征 for (CBCharacteristic *characteristic in service.characteristics) { NSLog(@"特征值:%@",characteristic.UUID.UUIDString); if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID]) { self.cbCharacteristic(characteristic); } if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID]) { [peripheral setNotifyValue:YES forCharacteristic:characteristic]; } } } - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error; { //这个方法比较好,这个是你发数据到外设的某一个特征值上面,并且响应的类型是 CBCharacteristicWriteWithResponse ,上面的官方文档也有,如果确定发送到外设了,就会给你一个回应,当然,这个也是要看外设那边的特征值UUID的属性是怎么设置的,看官方文档,人家已经说了,条件是,特征值UUID的属性:CBCharacteristicWriteWithResponse if (!error) { NSLog(@"说明发送成功,characteristic.uuid为:%@ 发送为%@",[characteristic.UUID UUIDString],characteristic.value); Byte byte2[] = {0xf0, 0x3d, 0x3d, 0x5d,0x02,0xf7}; NSData* data2 = [[NSData alloc] initWithBytes:byte2 length:3]; if ([characteristic.value isEqualToData:data2]) { NSLog(@"说明发送成功,characteristic.uuid为:%@ 发送为%@",[characteristic.UUID UUIDString],characteristic.value); } }else{ NSLog(@"发送失败了啊!characteristic.uuid为:%@ 原因:%@",[characteristic.UUID UUIDString],error); } //调用下面的方法后 会调用到代理的- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error [peripheral readValueForCharacteristic:characteristic]; } ///** // 根据特征读到数据 // // @param peripheral 读取到数据对应的设备 // @param characteristic 特征 // @param error 错误信息 // */ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID]) { NSData *data = characteristic.value; NSLog(@"%@",data); } } @end
2、一般在登录后的主窗口 初始化下面这个类 连接蓝牙和保存蓝牙相关数据 保存蓝牙设备值和特征值 发送数据会用到
SaveValueForBlueThooth.h
// // SaveValueForBlueThooth.h // SmartRobot // // Created by 杜文杰 on 2017/8/10. // Copyright © 2017年 appleLJ. All rights reserved. // #import <Foundation/Foundation.h> #import <CoreBluetooth/CoreBluetooth.h> #import "BlueToothManger.h" @interface SaveValueForBlueThooth : NSObject @property (nonatomic, strong) BlueToothManger *blueToothManager; // 设备 @property (nonatomic, strong) CBPeripheral *peripheral; // 特征值 @property (nonatomic, strong) CBCharacteristic *characteristic; // 连接成功标识 @property (nonatomic, assign) BOOL connectSeccess; + (instancetype)allocWithZone:(struct _NSZone *)zone; // 重新连接 - (void)bluetoothConnect; // 发送数据 - (void)postValueForBlueThoothWithString:(NSString *)valueWithStr; @end
SaveValueForBlueThooth.m
// // SaveValueForBlueThooth.m // SmartRobot // // Created by 杜文杰 on 2017/8/10. // Copyright © 2017年 appleLJ. All rights reserved. // #import "SaveValueForBlueThooth.h" // 通知特征值 static NSString * const kNotifyCharacteristicUUID = @"FFE1"; @implementation SaveValueForBlueThooth static SaveValueForBlueThooth *_instance; + (instancetype)allocWithZone:(struct _NSZone *)zone { // 也可以使用一次性代码 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (_instance == nil) { _instance = [super allocWithZone:zone]; } }); return _instance; } // 连接蓝牙设备 - (void)bluetoothConnect { [self.blueToothManager connectPeripheral:self.peripheral options:nil]; } // 发送数据 - (void)postValueForBlueThoothWithString:(NSString *)valueWithStr { NSLog(@"设备名:%@ 特征值 %@",self.peripheral.name,self.characteristic); // 特征值 NSString *tzName = self.characteristic.UUID.UUIDString; // 设备名 NSString *peripheraName = self.peripheral.name; if (tzName.length > 0 && peripheraName.length > 0) { // 写入数据 M_1_1000_ NSData *data = [valueWithStr dataUsingEncoding: NSUTF8StringEncoding]; [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse]; NSLog(@"%@",self.characteristic.UUID.UUIDString); NSLog(@"发送成功"); }else { [self bluetoothConnect]; NSLog(@"重新连接蓝牙"); } } @end
3、在跟控制器 主窗口中声明属性
(1)
@property (nonatomic, strong) BlueToothManger *blueToothManager; // 设备 @property (nonatomic, strong) CBPeripheral *peripheral; // 特征值 @property (nonatomic, strong) CBCharacteristic *characteristic; // 连接成功标识 @property (nonatomic, assign) BOOL connectSeccess; @property (nonatomic, strong) SaveValueForBlueThooth *saveValueForBlueThooth;
(2)在 viewDidLoad中调用连接蓝牙 并保存相关 发送需要的数据
- (void)viewDidLoad { [super viewDidLoad]; // 连接蓝牙 [self connectPeripheral]; }
(3)
#pragma mark - 蓝牙连接 - (void)connectPeripheral { // 单例记录发送数据 需要用的 设备值和特征值 _saveValueForBlueThooth = [[SaveValueForBlueThooth alloc]init]; // 初始化blueToothManager类连接蓝牙设备 self.blueToothManager = [[[BlueToothManger alloc]init]ShareBlueToothManger]; [self.blueToothManager centralManager]; __block __block typeof(SaveValueForBlueThooth *)saveValueForBlue = _saveValueForBlueThooth; // 连接蓝牙设备成功回调 // 存储设备值 self.blueToothManager.cbperipheral = ^(CBPeripheral *peripheral, BOOL connectSeccuss) { saveValueForBlue.peripheral = peripheral; saveValueForBlue.connectSeccess = connectSeccuss; }; // 存储特征值 self.blueToothManager.cbCharacteristic = ^(CBCharacteristic *characteristic) { saveValueForBlue.characteristic = characteristic; }; }
4、在需要发送数据的界面
(1)在 viewDidLoad中初始化类
self.blueThoothPostValue = [[SaveValueForBlueThooth alloc]init];
(2)发送按钮点击事件
//上 - (void)topBtnEvent{ NSLog(@"up"); [self.blueThoothPostValue postValueForBlueThoothWithString:@"E 1 "]; }