您的位置:首页 > 产品设计 > UI/UE

iOS--Core Bluetooth

2016-02-26 16:41 429 查看
Demo下载

在iOS中进行蓝牙传输应用开发常用的框架有如下几种:

GameKit.framework:iOS7之前的蓝牙通讯框架,从iOS7开始过期,但是目前多数应用还是基于此框架。

MultipeerConnectivity.framework:iOS7开始引入的新的蓝牙通讯开发框架,用于取代GameKit。

CoreBluetooth.framework:功能强大的蓝牙开发框架,要求设备必须支持蓝牙4.0。

现在CoreBluetooth越来越受欢迎,准备研究一下。

CoreBluetooth设计是类似于客户端-服务器端的设计,作为服务器端的设备称为外围设备(Peripheral),作为客户端的设备叫做中央设备(Central),CoreBlueTooth整个框架就是基于这两个概念来设计的。

外围设备和中央设备在CoreBluetooth中使用CBPeripheralManager和CBCentralManager表示。

CBPeripheralManager:外围设备通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务和特征。
CBCentralManager:中央设备使用外围设备的数据。中央设备扫描到外围设备后会就会试图建立连接,一旦连接成功就可以使用这些服务和特征。
外围设备和中央设备之间交互的桥梁是服务(CBService)和特征(CBCharacteristic),二者都有一个唯一的标识UUID(CBUUID类型)来唯一确定一个服务或者特征,每个服务可以拥有多个特征,下面是他们之间的关系:



图片来源于网络
1、创建一个外围设备通常分为以下几个步骤:

创建外围设备CBPeripheralManager对象并指定代理。
创建特征CBCharacteristic、服务CBSerivce并添加到外围设备
外围设备开始广播服务(startAdvertisting:)。
和中央设备CBCentral进行交互。

2、中央设备的创建一般可以分为如下几个步骤:

创建中央设备管理对象CBCentralManager并指定代理。
扫描外围设备,一般发现可用外围设备则连接并保存外围设备。
查找外围设备服务和特征,查找到可用特征则读取特征数据。

外围设备,代码如下
#import "JLPeripheralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>

#define ServiceUUID @"A48D3B5C-353D-4093-8821-DDDEBFEFEA32"
#define CharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC"

@interface JLPeripheralViewController ()<CBPeripheralManagerDelegate>
- (IBAction)Start:(UIButton *)sender;
- (IBAction)Send:(UIButton *)sender;

@end

@implementation JLPeripheralViewController
{
CBPeripheralManager *_PeripheralManager;// 外围设备管理器
CBMutableCharacteristic *_PerCharacteristic; // 特征值
NSMutableArray <CBCentral *>*_centrals;// 存储订阅特征的中心设备

}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_centrals = [NSMutableArray array];
}
- (IBAction)Start:(UIButton *)sender {
NSLog(@"1111");
_PeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}

- (IBAction)Send:(UIButton *)sender {
[self _updateCharacteristicValue];
}
#pragma mark - CBPeripheralManagerDelegate
// 外围设备状态发生变化
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
NSLog(@"%ld",peripheral.state);
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
NSLog(@"蓝牙打开");
// 添加服务
[self _addService];
}else{
NSLog(@"蓝牙未开启,或不支持");
}
}
// 添加服务后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
if (!error) {
NSLog(@"添加服务成功");
// 服务添加后开始广播
[peripheral startAdvertising:@{CBAdvertisementDataLocalNameKey:@"XIAOLE's Iphone"}];
}else{
NSLog(@"添加服务失败error:%@",error);
}
}
-(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
if (!error) {
NSLog(@"服务启动");
}else{
NSLog(@"服务启动失败:%@",error);
}
}
// 中心设备订阅特征调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心设备订阅特征central:%@,characteristic:%@",central,characteristic);
if (central) {
// 保存中心设备
[_centrals addObject:central];
}
}
// 中心设备取消订阅特征
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心设备取消订阅特征:central%@,characteristic:%@",central,characteristic);
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(CBATTRequest *)request{
NSLog(@"didReceiveWriteRequests");
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dic{
NSLog(@"willRestoreState");
}
// 更新特征时调用
-(void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
{
NSLog(@"ReadyToUpdateSubscribers");
}
#pragma mark - -
- (void)_addService
{
NSLog(@"添加服务");
// 特征
_PerCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:CharacteristicUUID] properties:CBCharacteristicPropertyNotify | CBCharacteristicPropertyRead |CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable];
// 创建服务
CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:ServiceUUID] primary:YES];
// 设置服务的特征
[service setCharacteristics:@[_PerCharacteristic]];
// 外围设备添加服务
[_PeripheralManager addService:service];
}

- (void)_updateCharacteristicValue
{
NSLog(@"更新特征值");
// 更新特征值
NSString *str = [@"特征值:" stringByAppendingString:[NSString stringWithFormat:@"%@",[NSDate date]]];
[_PeripheralManager updateValue:[str dataUsingEncoding:NSUTF8StringEncoding]  forCharacteristic:_PerCharacteristic onSubscribedCentrals:_centrals];
}
@end
中心设备代码如下
#import "JLCentralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#define ServiceUUID @"A48D3B5C-353D-4093-8821-DDDEBFEFEA32"
#define CharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC"
@interface JLCentralViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>//中央设备管理器代理,外围设备代理
- (IBAction)Start:(UIButton *)sender;

@end

@implementation JLCentralViewController
{
CBCentralManager *_CentralManager;// 中央设备管理器
NSMutableArray *_peripherals;// 发现的外围设备
}
- (void)viewDidLoad {
[super viewDidLoad];
_peripherals = [NSMutableArray array];
}

- (IBAction)Start:(UIButton *)sender {
// 设置代理为self,并将代理回调放在主线程中
_CentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
#pragma mark - CBCentralManagerDelegate
// 必须实现的代理方法,中央设备管理器的状态发生改变时调用
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{

// 在这里判断CBCentralManager的stutas,并作出相应处理
/*
stutas为枚举值,有以下几种
typedef NS_ENUM(NSInteger, CBCentralManagerState) {
CBCentralManagerStateUnknown = 0,
CBCentralManagerStateResetting,
CBCentralManagerStateUnsupported,
CBCentralManagerStateUnauthorized,
CBCentralManagerStatePoweredOff,
CBCentralManagerStatePoweredOn,
};
*/
NSLog(@"%ld",central.state);
if (central.state == CBCentralManagerStatePoweredOn) {
NSLog(@"蓝牙设备已打开");
// 扫描外围设备,serviceUUIDs设为nil会返回所有能扫描到的设备
[central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
NSLog(@"正在扫描...");
}else{
NSLog(@"蓝牙未开启,或不支持");
}
}
-(void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict
{
NSLog(@"RestoreState%@",dict);
}
// 发现外围设备
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"发现外围设备");
// 停止扫描
[central stopScan];
NSLog(@"扫描停止");
if (![_peripherals containsObject:peripheral]) {
[_peripherals addObject:peripheral];
}
// 与外围设备建立连接
[central connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}];
NSLog(@"开始连接外围设备");
}
// 连接上外围设备
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"连接上外围设备");
// 设置外围设备的代理
peripheral.delegate = self;
// 外围设备搜寻服务,serviceUUIDs设为nil为搜索全部服务
[peripheral discoverServices:@[[CBUUID UUIDWithString:ServiceUUID]]];
NSLog(@"外围设备搜寻服务");
}
// 丢失与外围设备的连接
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"丢失连接");
}
// 连接外围设备失败
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"连接失败,%@",error);
}
#pragma mark - CBPeripheralDelegate
// 发现服务调用
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (!error) {
NSLog(@"发现服务");
// 找到指定服务,因为我前面已经写了搜寻指定服务,所以services应该有一个我指定的服务。写遍历,只是更好的认识外围设备--服务--特征之间的关系,后面搜索特征亦如此
for (CBService *service in peripheral.services) {
if ([service.UUID.UUIDString isEqualToString:ServiceUUID]) {
NSLog(@"找到指定服务");
// 寻找服务中的指定特征,characteristicUUIDs=nil则搜寻服务的所有特征
[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CharacteristicUUID]] forService:service];
}
}
}else{
NSLog(@"未发现服务:%@",error);
}
}
// 发现特征调用
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error
{
if (!error) {
NSLog(@"发现特征");
// 查找指定特征
for (CBCharacteristic *charcter in service.characteristics) {
if ([charcter.UUID.UUIDString isEqualToString:CharacteristicUUID]) {
NSLog(@"找到指定特征");
// 去到指定特征,根据特征值的属性(可通知,可读,可写。。),可以做相应的事
/**  通知  调用代理peripheral:didUpdateNotificationStateForCharacteristic:error
**/
[peripheral setNotifyValue:YES forCharacteristic:charcter];
/**  读  调用代理peripheral:didUpdateValueForCharacteristic:error**/
[peripheral readValueForCharacteristic:charcter];
/**  写  调用peripheral:didWriteValueForCharacteristic:error **/
/*
typedef NS_ENUM(NSInteger, CBCharacteristicWriteType) {
CBCharacteristicWriteWithResponse = 0,// 写入成功有返回
CBCharacteristicWriteWithoutResponse,//写入成功无返回
};
*/
[peripheral writeValue:[@"CoreBlueTooth Demo" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:charcter type:CBCharacteristicWriteWithResponse];
}
}
}
}
//  外围设备管理器接收到中心设备是否订阅特征值后的回调
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"特征值:%@",characteristic);
}
// 调用readValueForCharacteristic或外围设备更新特征值都会调用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"特征值:%@",characteristic);
}
//调用writeValue:forCharacteristic:type且type的值为CBCharacteristicWriteWithResponse 后的回调
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{

}
@end


代码其实并没有很复杂,中心设备和外围设备的相互交流大概流程是这样的

外围设备管理器设置服务,特征 -->
外围设备管理器发出广播 -->
中心设备管理器发现外围设备 -->
找到需要的外围设备 -->
建立连接 --> 外围设备设置代理(这里在JLCentralViewController中设置)-->
外围设备寻找服务,特征这里在JLCentralViewController中设置) -->
外围设备发送通知,写,读等操作请求(这里在JLCentralViewController中设置) -->
外围设备管理器收到请求(didReceive...Requests),并调用代理方法 -->
外围设备管理器响应请求(respondToRequest)-->
外围设备接收到响应的回调(代理方法,这里在JLCentralViewController中设置)。

Demo下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: