--- .h文件 ---
#import
//BLIE4.0 蓝牙库
#import
/**
蓝牙链接状态
@param state 状态
*/
typedef void (^BLELinkBlock)(NSString *state);
/**
蓝牙返回数据
@param array 返回数据
*/
typedef void (^BLEDataBlock)(NSMutableArray *array);
typedef enum BLEState_NOW{
BLEState_Successful = 0,//连接成功
BLEState_Disconnect = 1, // 失败
BLEState_Normal, // 未知
}BLEState_NOW;
/**
蓝牙连接成功 或者断开
*/
typedef void(^BLEStateBlcok)(int number);
@interface BLEModel : NSObject
/**
外设名称 外设UUID 外设读取数据 UUID 外设写入UUID
*/
@property (nonatomic,strong) NSString *BLEName; //蓝牙硬设名称
@property (nonatomic,strong) NSString *BLEServiceID; //蓝牙硬设设备ID
@property (nonatomic,strong) NSString *BLEServiceReadID;//蓝牙硬设读取权限ID
@property (nonatomic,strong) NSString *BLEServiceWriteID;//蓝牙硬设写入信息ID
@property (nonatomic,copy) NSString *connectState;//蓝牙连接状态
@property (nonatomic,copy) BLELinkBlock linkBlcok; //蓝牙状态回调
@property (nonatomic,copy) BLEDataBlock dataBlock; //蓝牙硬设返回数据
@property (nonatomic,copy) BLEStateBlcok stateBlock; //蓝牙连接成功失败
/**
* 开始扫描
*/
-(void)startScan;
/**
主动断开链接
*/
-(void)cancelPeripheralConnection;
/**
发送命令
*/
- (void) sendData:(NSData *)data;
@end
--- .h文件 ---
--- .m文件 ---
#import "BLEModel.h"
//#import "BLEIToll.h"
@interface BLEModel ()
/**
* 蓝牙连接必要对象
*/
@property (nonatomic, strong) CBCentralManager *centralMgr; //蓝牙操作对象
@property (nonatomic, strong) CBPeripheral *discoveredPeripheral; //获取蓝牙设备信息
@property (strong, nonatomic) CBCharacteristic* writeCharacteristic; //蓝牙设备读写服务操作对象
@property (nonatomic,assign) BOOL isInitiativeDisconnect;//主动断开连接
@end
@implementation BLEModel
- (instancetype)init
{
self = [super init];
if (self) {
_centralMgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
}
return self;
}
/**
* 开始扫描
*/
- (void)startScan{
_centralMgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
}
/**
* 停止扫描
*/
-(void)stopScan
{
[_centralMgr stopScan];
}
#pragma mark - 蓝牙的状态
/**
* -- 初始化成功自动调用
* -- 必须实现的代理,用来返回创建的centralManager的状态。
* -- 注意:必须确认当前是CBCentralManagerStatePoweredOn状态才可以调用扫描外设的方法:
scanForPeripheralsWithServices
*/
// 2. 搜索扫描外围设备
// CBCentralManagerDelegate 必须实现的代理函数
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBManagerStateUnknown:
{
//NSLog(@"无法获取设备的蓝牙状态");
self.connectState = kCONNECTED_UNKNOWN_STATE;
}
break;
case CBManagerStateResetting:
{
//NSLog(@"蓝牙重置");
self.connectState = kCONNECTED_RESET;
}
break;
case CBManagerStateUnsupported:
{
//NSLog(@"该设备不支持蓝牙");
self.connectState = kCONNECTED_UNSUPPORTED;
}
break;
case CBManagerStateUnauthorized:
{
//NSLog(@"未授权蓝牙权限");
self.connectState = kCONNECTED_UNAUTHORIZED;
}
break;
case CBManagerStatePoweredOff:
{
//NSLog(@"蓝牙已关闭");
self.connectState = kCONNECTED_POWERED_OFF;
}
break;
case CBManagerStatePoweredOn:
{
//NSLog(@"蓝牙已打开");
self.connectState = kCONNECTED_POWERD_ON;
[_centralMgr scanForPeripheralsWithServices:nil options:nil];
}
break;
default:
{
//NSLog(@"未知的蓝牙错误");
self.connectState = kCONNECTED_ERROR;
}
break;
}
self.linkBlcok(self.connectState);
//[self getConnectState];
}
#pragma mark -- CBCentralManagerDelegate
#pragma mark- 发现设备 扫描设备,连接
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"name:%@",peripheral);
/**
当扫描到蓝牙数据为空时,停止扫描
*/
if (!peripheral || !peripheral.name || ([peripheral.name isEqualToString:@""])) {
return;
}
/**
当扫描到服务UUID与设备UUID相等时,进行蓝牙与设备链接
*/
if ((!self.discoveredPeripheral || (self.discoveredPeripheral.state == CBPeripheralStateDisconnected))&&([peripheral.name isEqualToString:_BLEName])) {
self.discoveredPeripheral = [peripheral copy];
//self.peripheral.delegate = self;
NSLog(@"connect peripheral: %@",peripheral);
// 3.连接外围设备
// 连接设备(.h中声明出去的接口, 一般在点击设备列表连接时调用)
[self.centralMgr connectPeripheral:peripheral options:nil];
}
}
#pragma park- 连接外设--成功,扫描services
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
if (!peripheral) {
return;
}
//连接成功后停止扫描,节省内存
[self.centralMgr stopScan];
self.stateBlock(BLEState_Successful);
NSLog(@"peripheral did connect: %@",peripheral);
// 是 peripheral.delegate = self; 还是 self.discoveredPeripheral有待考察
//4.扫描外设的服务
/**
-- 外设的服务、特征、描述等方法是CBPeripheralDelegate的内容,所以要先设置代理peripheral.delegate = self
-- 参数表示你关心的服务的UUID,比如我关心的是"FFE0",参数就可以为@[[CBUUID UUIDWithString:@"FFE0"]].那么didDiscoverServices方法回调内容就只有这两个UUID的服务,不会有其他多余的内容,提高效率。nil表示扫描所有服务
-- 成功发现服务,回调didDiscoverServices
*/
[self.discoveredPeripheral setDelegate:self];
[self.discoveredPeripheral discoverServices:@[[CBUUID UUIDWithString:@"你要用的服务UUID"]]];
}
#pragma mark 连接外设——失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%@", error);
}
#pragma mark 取消与外设的连接回调 外设断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
NSLog(@"外设断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);
self.stateBlock(BLEState_Disconnect);
//重连外设
if (!self.isInitiativeDisconnect) {
[self.centralMgr connectPeripheral:peripheral options:nil];
}
}
// 4. 获得外围设备的服务
#pragma mark - 扫描service
#pragma mark 发现服务回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
NSArray *services = nil;
if (peripheral != self.discoveredPeripheral) {
NSLog(@"Wrong Peripheral.\n");
return ;
}
if (error != nil) {
NSLog(@"Error %@\n", error);
return ;
}
services = [peripheral services];
NSLog(@"%@",services);
if (!services || ![services count]) {
NSLog(@"No Services");
return ;
}
// 遍历服务
for (CBService *service in services) {
NSLog(@"该设备的service:%@",service);
// [[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服务UUID"]]
if ([[service.UUID UUIDString] isEqualToString:_BLEServiceID]) {
[peripheral discoverCharacteristics:nil forService:service];
return ;
}
}
}
//5、获得服务的特征;
#pragma mark 发现特征回调
/**
-- 发现特征后,可以根据特征的properties进行:读readValueForCharacteristic、写writeValue、订阅通知setNotifyValue、扫描特征的描述discoverDescriptorsForCharacteristic。
**/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
NSLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]);
return;
}
// 遍历服务的特征
for (CBCharacteristic *characteristic in service.characteristics) {
NSLog(@"\n>>>\t特征UUID FOUND(in 服务UUID:%@): %@ (data:%@)",service.UUID.description,characteristic.UUID,characteristic.UUID.data);
/**
>>> 特征UUID FOUND(in 服务UUID:FFE0): FFE1 (data:
>>> 特征UUID FOUND(in 服务UUID:FFE0): FFE2 (data:
*/
/*
根据特征不同属性去读取或者写
if (c.properties==CBCharacteristicPropertyRead) {
}
if (c.properties==CBCharacteristicPropertyWrite) {
}
if (c.properties==CBCharacteristicPropertyNotify) {
}
*/
/*
设备读取UUID 这里根据UUID判断 不一定对根据项目需求
*/
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:_BLEServiceReadID]]) {
self.writeCharacteristic = characteristic;
// 订阅, 实时接收
[_discoveredPeripheral setNotifyValue:YES forCharacteristic:self.writeCharacteristic];
}
/**
设备写入UUID 这里根据UUID判断 不一定对根据项目需求
*/
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:_BLEServiceWriteID]]) {
self.writeCharacteristic = characteristic;
NSData *data = [@"硬件工程师给我的指令, 发送给蓝牙该指令, 蓝牙会给我返回一条数据" dataUsingEncoding:NSUTF8StringEncoding];
// 将指令写入蓝牙
[_discoveredPeripheral writeValue:data forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];
}
/**
-- 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
*/
[peripheral discoverDescriptorsForCharacteristic:characteristic];
}
}
// 已经发现特征的描述
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
NSLog(@"didDiscoverDescriptorsForCharacteristic:%@",characteristic);
for (CBDescriptor *d in characteristic.descriptors) {
NSLog(@"Descriptor UUID:%@",d.UUID);
}
}
// 6.从外围设备读取数据
#pragma mark - 读取数据 获取值
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(@"didUpdateValueForCharacteristic error : %@", error.localizedDescription);
return;
}
// characteristic.value就是蓝牙给我们的值(我这里是json格式字符串)
NSData *data = characteristic.value;
// 通过工具做处理
// 或者NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];传出去即可
// NSMutableArray *dataArr = [BLEIToll convertDataToHexStr:data];
// 通过工具类处理 得到的Array 传出去
NSMutableArray *dataArr = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
self.dataBlock(dataArr);
}
#pragma mark - 中心读取外设实时数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (characteristic.isNotifying) {
[peripheral readValueForCharacteristic:characteristic];
} else {
NSLog(@"Notification stopped on %@. Disconnecting", characteristic);
NSLog(@"%@", characteristic);
[_centralMgr cancelPeripheralConnection:peripheral];
}
}
#pragma mark - 主动断开连接
-(void)cancelPeripheralConnection{
self.isInitiativeDisconnect = YES;
if (self.discoveredPeripheral) {//已经连接外设,则断开
[self.centralMgr cancelPeripheralConnection:self.discoveredPeripheral];
}else{//未连接,则停止搜索外设
[self.centralMgr stopScan];
}
}
/**
发送命令
*/
- (void) sendData:(NSData *)data{
/**
通过CBPeripheral 类 将数据写入蓝牙外设中,蓝牙外设所识别的数据为十六进制数据,在ios系统代理方法中将十六进制数据改为 NSData 类型 ,但是该数据形式必须为十六进制数 0*ff 0*ff格式 在iToll中有将 字符串转化为 十六进制 再转化为 NSData的方法
*/
[self.discoveredPeripheral writeValue:data forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
}
//向peripheral中写入数据后的回调函数
- (void)peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
//该方法可以监听到写入外设数据后的状态
if (error) {
NSLog(@"didWriteValueForCharacteristic error : %@", error.localizedDescription);
return;
}
NSLog(@"write value success : %@", characteristic);
}
@end
--- .m文件 ---
--- ViewControll 使用 ---
#import "ViewController.h"
#import "BLEModel.h"
#import "BLEIToll.h"
@interface ViewController ()
@property (nonatomic,strong) BLEModel *manager;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor lightGrayColor];
[self initNavTitle];
[self BluetoothConnection];
}
/**
设计导航
*/
- (void)initNavTitle{
self.navigationItem.title = @"空气质量";
//蓝牙图标
UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 20)];
titleLabel.textColor = [BLEIToll colorWithHexString:@"#6ccc8f"];
titleLabel.text = @"未连接";
titleLabel.font = [UIFont systemFontOfSize:12];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:titleLabel];
}
/**
蓝牙初始化
*/
- (void)BluetoothConnection{
WeakSelf;
_manager = [[BLEModel alloc]init];
_manager.BLEName = PMServiceName; //蓝牙硬设名称
_manager.BLEServiceID = PMServiceUUID; //蓝牙硬设设备ID
_manager.BLEServiceReadID = PMServiceUUID_Receive;
_manager.BLEServiceWriteID = PMServiceUUID_Send;
_manager.linkBlcok = ^(NSString *state){
NSLog(@"++++++++:%@",state);
};
_manager.dataBlock = ^(NSMutableArray *array){
// NSLog(@"%@",array);
if (array.count >= 20) {
BLEIToll *itool = [[BLEIToll alloc]init];
if ([array[0] isEqualToString:@"42"] && [array[1] isEqualToString:@"4d"]) {
NSLog(@"-----------:%@",[itool handleTheBLEFirstData:array]);
}else{
NSLog(@"}}}}}}}}}}}:%@",[itool handleTheBLEFirstData:array]);
}
}
};
_manager.stateBlock = ^(int number){
NSLog(@"%d",number);
[weakSelf BLEStateInt:number];
};
/*
发送一个 0xFA 0xE4 Ox33 的命令
*/
/*
NSData *data = [[BLEIToll alloc] stringToByte:@"FAE433"];
NSLog(@"写入数据%@",data);
[_manager sendData:data];
*/
}
- (void)BLEStateInt:(int) state{
switch (state) {
case BLEState_Successful:
{
//连接成功
UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 20)];
titleLabel.textColor = [BLEIToll colorWithHexString:@"#6ccc8f"];
titleLabel.text = @"已连接";
titleLabel.font = [UIFont systemFontOfSize:12];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:titleLabel];
}
break;
case BLEState_Disconnect:
{
//外设断开连接
UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 20)];
titleLabel.textColor = [BLEIToll colorWithHexString:@"#6ccc8f"];
titleLabel.text = @"未连接";
titleLabel.font = [UIFont systemFontOfSize:12];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:titleLabel];
}
break;
default:
break;
}
}
@end
--- ViewControll 使用 ---
下载链接
https://download.csdn.net/my/uploads/1/1
或者搜索 XJP蓝牙4.0封装