最近写一个蓝牙项目 初步实现一下蓝牙设备连接交互,后期继续完善。。。。
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);//最常用的场景是查找某一个前缀开头的设备 moguif ([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的属性:CBCharacteristicWriteWithResponseif (!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 SaveValueForBlueThoothstatic 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_\rNSData *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\r"]; }