IOS BLE 开发

一.关键词

  • 中央设备:中央设备用于管理外设,一个中央设备可以同时连接管理多个外设。
  • 中心设备管理(CBCentralManager):管理外设的工具,提供扫描连接外设等方法。
  • 外设(CBPeripheral):如蓝牙耳机,音响,打印机等,外设主动广播数据(advertisementData)描述其设备的基本信息,如此设备是什么,叫什么,提供什么样的服务(CBService)(类似于电台广播,不管是否有用户,都会广播信号以描述其电台信息)。
  • 外设管理(CBPeripheralManager):管理外设,给外设添加服务
  • 服务(CBService):一个外设至少有一个服务,一个服务包含多个特征,每个服务由唯一的一个UUID确定。
  • 特征(CBCharacteristic):设备间通讯的最小单元或者说是一个通讯通道,每个特征由唯一的一个UUID确定。
  • 特征值:特征存储的数据。
  • 特征属性:用于描述特征的权限,如读,写等,以下是oc特征属性的枚举:
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
    CBCharacteristicPropertyBroadcast                                               = 0x01,
    CBCharacteristicPropertyRead                                                    = 0x02,
    CBCharacteristicPropertyWriteWithoutResponse                                    = 0x04,
    CBCharacteristicPropertyWrite                                                   = 0x08,
    CBCharacteristicPropertyNotify                                                  = 0x10,
    CBCharacteristicPropertyIndicate                                                = 0x20,
    CBCharacteristicPropertyAuthenticatedSignedWrites                               = 0x40,
    CBCharacteristicPropertyExtendedProperties                                      = 0x80,
    CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)     = 0x100,
    CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)   = 0x200
};
  • 广播数据(advertisementData):用于描述外设基本信息

二.工作流程

外设工作流程

  1. 建立外设管理(CBPeripheralManager):需要实现CBPeripheralManagerDelegate协议。
  2. 新建添加服务(CBMutableService)设置服务特征(CBCharacteristic),后续通过特征通讯。
  3. 广播服务。

中心设备工作流程

  1. 建立中心设备管理(CBCentralManager):需实现CBCentralManagerDelegate,CBPeripheralDelegate协议
  2. 扫描外设。
  3. 连接外设。
  4. 扫描外设服务。
  5. 选择使用外设服务。
  6. 获取服务特征(即获取了通讯通道)。
  7. 选择使用特征进行通讯。

通讯流程

三.上代码

外设

//
//  BLECBPeripheral.h
//  BLE
//
//  Created by chenguibang on 2017/3/15.
//  Copyright © 2017年 chenguibang. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface BLECBPeripheral : NSObject<CBPeripheralManagerDelegate>
@property(nonatomic,strong) CBPeripheralManager *peripheralManager;

+(id)shared;

-(void)setup;

-(void)addSe;
-(void)adv;
@end

//
//  BLECBPeripheral.m
//  BLE
//
//  Created by chenguibang on 2017/3/15.
//  Copyright © 2017年 chenguibang. All rights reserved.
//

#import "BLECBPeripheral.h"
#define kPeripheralName @"Kenshin Cui's Device" //外围设备名称
#define kServiceUUID @"C4FB2349-72FE-4CA2-94D6-1F3CB16331EE" //服务的UUID
#define kCharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC" //特征的
@implementation BLECBPeripheral

+(id)shared{
    static dispatch_once_t onceToken;
    static BLECBPeripheral *per = nil;
    dispatch_once(&onceToken, ^{
        per = [[BLECBPeripheral alloc]init];
    });
    return per;
    
}

-(void)setup{
    self.peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
}


-(void)addSe{
    CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID];
    CBMutableCharacteristic *characteristicM=[[CBMutableCharacteristic alloc]initWithType:characteristicUUID properties:CBCharacteristicPropertyNotify|CBCharacteristicPropertyWriteWithoutResponse|CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable|CBAttributePermissionsWriteable|CBAttributePermissionsReadEncryptionRequired|CBAttributePermissionsWriteEncryptionRequired];
    CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
    //创建服务
    CBMutableService *serviceM=[[CBMutableService alloc]initWithType:serviceUUID primary:YES];
    //设置服务的特征
    [serviceM setCharacteristics:@[characteristicM]];
    
    /*将服务添加到外围设备*/
    [self.peripheralManager addService:serviceM];
}


-(void)adv{
    //添加服务后开始广播
    NSDictionary *dic=@{CBAdvertisementDataLocalNameKey:kPeripheralName};//广播设置
    [self.peripheralManager startAdvertising:dic];//开始广播
}

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    
    switch (peripheral.state) {
        case CBManagerStatePoweredOn:
            NSLog(@"BLE已打开.");
        
            break;
            
        default:
            NSLog(@"BLE已打开.异常");
            break;
    }
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    NSLog(@"添加服务成功");
}

-(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{
    NSLog(@"广播成功");
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"有服务订阅特征值");
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"有服务取消订阅特征值");
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
    NSLog(@"收到读请求");
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests{
    NSLog(@"收到写请求");
    
}

@end


中央设备

//
//  BLETool.h
//  BLEOCChat
//
//  Created by chenguibang on 2017/3/14.
//  Copyright © 2017年 chenguibang. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

typedef void(^ErrorBlcok)(NSError* error);

@interface BLETool : NSObject<CBCentralManagerDelegate,CBPeripheralDelegate>
@property(nonatomic,strong)CBCentralManager *centerManager;
@property(nonatomic,strong)NSMutableArray<CBPeripheral*> *peripherals;
@property(nonatomic,strong)NSMutableArray<CBService*> *sevices;
@property(nonatomic,strong)NSMutableArray<CBCharacteristic *>*characters;
@property(nonatomic,copy)ErrorBlcok errorBlcok;
+(id)shared;
-(void)setup;
-(void)scanfPer:(NSUInteger)timeout;
-(void)stopScanf;
-(void)connectTo:(CBPeripheral*)peripheral reuslt:(void(^)())result;
-(void)disconnect:(CBPeripheral*)peripheral;
-(void)discoverServicesFor:(CBPeripheral*)peripheral;
-(void)discoverCharactersFor:(CBService *)service In:(CBPeripheral*)peripheral;


-(void)write:(CBPeripheral*)peripheral forCharacteristic:(CBCharacteristic *)characteristic value:(NSData *)data;
@end


//
//  BLETool.m
//  BLEOCChat
//
//  Created by chenguibang on 2017/3/14.
//  Copyright © 2017年 chenguibang. All rights reserved.
//

#import "BLETool.h"


#define findMeServiceUUID             [CBUUID UUIDWithString:@"1802"]
#define genericAccessServiceUUID      [CBUUID UUIDWithString:@"1800"]
#define linkLossServiceUUID           [CBUUID UUIDWithString:@"1803"]
#define deviceNameCharacteristicUUID  [CBUUID UUIDWithString:@"2A00"]
#define alertLevelCharacteristicUUID  [CBUUID UUIDWithString:@"2A06"]
#define BT_ALERT_LEVEL_NONE 0
#define BT_LEVEL_MILD 1
#define BT_ALERT_LEVEL_HIGH 2
#define BT_ALERT_LEVEL_RESERVED(LVL) LVL

@interface BLETool(){
//    CBCentralManager *centerManager;
    
}

@end

@implementation BLETool


+(id)shared{
    static dispatch_once_t onceToken;
    static BLETool *tool;
    dispatch_once(&onceToken, ^{
        tool = [[BLETool alloc]init];
        [tool setup];
    });
    return tool;
}
-(void)setup{
    
//    1.建立中心管理
    self.centerManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    self.centerManager.delegate  = self;//设置代理
    self.peripherals = [NSMutableArray array];
    self.sevices = [NSMutableArray array];
    self.characters = [NSMutableArray array];


}

-(void)scanfPer:(NSUInteger)timeout{
    

    if (self.centerManager.isScanning) {
        [[self mutableArrayValueForKey:@"peripherals"]removeAllObjects];
        [self.centerManager stopScan];
    }
//    2.扫描外设
    [self.centerManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithInt:1],CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithInt:1]}];
}
-(void)stopScanf{
    [self.centerManager stopScan];
}

-(void)connectTo:(CBPeripheral*)peripheral reuslt:(void(^)())result{
    if (self.centerManager.isScanning) {
        [self.centerManager stopScan];
    }
    //    3.连接外设
    if (peripheral.state != CBPeripheralStateDisconnected) {
        NSLog(@"该设备暂时不能连接");
        
        self.errorBlcok([NSError errorWithDomain:NSURLErrorDomain code:1 userInfo:@{@"msg":@"外设暂时状态不可连接"}]);
    
    }else{
        [self.centerManager connectPeripheral:peripheral options:nil];
    }
    
    
}
-(void)disconnect:(CBPeripheral *)peripheral{
    [self.centerManager cancelPeripheralConnection:peripheral];
}

-(void)discoverServicesFor:(CBPeripheral*)peripheral{
    NSMutableArray *sevices = [self mutableArrayValueForKeyPath:@"sevices"];
    [sevices removeAllObjects];
    peripheral.delegate = self;
    [peripheral discoverServices:nil];
}



-(void)write:(CBPeripheral*)peripheral forCharacteristic:(CBCharacteristic *)characteristic value:(NSData *)data{
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    
    switch (central.state) {
        case CBManagerStateUnknown:
            
            break;
        case CBManagerStateResetting:
            
            break;
            
        case CBManagerStateUnsupported:
            
            break;
            
        case CBManagerStateUnauthorized:
            
            break;
            
        case CBManagerStatePoweredOff:
            
            break;
            
        case CBManagerStatePoweredOn:
//            [central scanForPeripheralsWithServices:nil options:nil];
            break;
        default:
            break;
    }
    
    
    NSLog(@"scanState  :  %ld \n" , (long)central.state);
}

-(void)discoverCharactersFor:(CBService *)service In:(CBPeripheral*)peripheral;{
    NSMutableArray *characters = [self mutableArrayValueForKeyPath:@"characters"];
    [characters removeAllObjects];
    [peripheral discoverCharacteristics:nil forService:service];
}



//advertisementData 外设主动发送的广播数据  RSSI 信号强度单位是dbm
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    NSMutableArray *peripherals = [self mutableArrayValueForKeyPath:@"peripherals"];
    if (![self.peripherals containsObject:peripheral]) {
        
        [peripherals addObject:peripheral];
//        [[self mutableArrayValueForKeyPath:@"peripherals"] addObject:peripheral];
        
    }else{
      NSUInteger index =  [peripherals indexOfObject:peripheral];
        [peripherals replaceObjectAtIndex:index withObject:peripheral];
        
//        [[self mutableArrayValueForKeyPath:@"peripherals"] replaceObjectAtIndex:[self.peripherals indexOfObject:peripheral] withObject:peripheral];
        
    }
    NSLog(@"scan DisconnectPeripherals:  %@ \n",self.peripherals);
//  NSLog(@"uuid : %@\n",peripheral.identifier.UUIDString);


}

-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    NSLog(@"连接成功");
    self.errorBlcok([NSError errorWithDomain:NSURLErrorDomain code:9999 userInfo:@{@"msg":@"连接成功"}]);

}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    self.errorBlcok([NSError errorWithDomain:NSURLErrorDomain code:9999 userInfo:@{@"msg":@"连接失败"}]);
}


-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
}

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
     NSLog(@"发现服务");

    if (!error) {
        NSMutableArray *sevices = [self mutableArrayValueForKeyPath:@"sevices"];
        [sevices addObjectsFromArray:peripheral.services];
        for (CBService *service in peripheral.services) {
            NSLog(@"%@",service.UUID);
            [peripheral discoverCharacteristics:nil forService:service];
        }
    }else{
        self.errorBlcok([NSError errorWithDomain:NSURLErrorDomain code:9999 userInfo:@{@"msg":@"查找失败"}]);
    }
    
    
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error{
    NSMutableArray *characters = [self mutableArrayValueForKeyPath:@"characters"];
    [characters addObjectsFromArray:service.characteristics];
}


-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
    
}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
}

@end


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 与外围设备交互的最佳实践 原文:Best Practices for Interacting with a Rem...
    cocoajin阅读 1,893评论 0 6
  • 经过一段长期的学习,从开始猥琐发育到最后最后终于来真泰瑞。 倒入头文件 BLE蓝牙使用的是coreBluetoot...
    keep刘阅读 3,677评论 4 9
  • iOS开发之蓝牙通讯 一、引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯...
    隐身人阅读 2,387评论 3 0
  • 做蓝牙开发也有一年多的时间了,从单个BLE外设到BLE Mesh开发,想利用开发的空余时间整理一下零零碎碎的蓝牙开...
    makemake阅读 2,599评论 3 1
  • 个人也好,一个组织也好,必须要有大局观,必须要有抓大放小的认识,必须要有容错的胸襟,气度或机制。如果想事事完美,一...
    闲亭观雨阅读 657评论 0 1