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

ios 蓝牙4.0开发(CoreBlueTooth)

2016-04-29 18:18 786 查看
一、蓝牙开发引入

情景 : 蓝牙(Center)监听心跳仪(Peripheral)发送数据,发送到服务器。



心跳仪->外设(被连接的设备),蓝牙->中心(发起连接)

类似,客户端和服务器之间的关系(ios设备和非ios设备之间的交互)。

二、关于蓝牙的一些术语

1、Center : 中心 (发起连接的是中心)

2、Peripheral:外设(被链接的设备称之为外设)

3、service and characteristic (服务和特征)

每个设备都会提供服务和特征。每个外设都会提供很多服务,每个服务都会包含很多字段,这些字段都是有权限的,权限大致为:read/write/notify,就是我们链接设备后具体需要操作的内容.

4、Description : 每个characteristic可以对应一个或多个Description,用于描述特征(characteristic)的信息或属性。

5、BLE: blue low energy 蓝牙4.0低耗电

6、4.0 BLE : 开发使用CoreBluetooth 框架 (ios6.0以上)

7、MFL认证: make for ipad /iphone/ itouch (专门为苹果设备制作的设备)

三、蓝牙的中心模式、外设模式、工作状态

1、中心模式流程

主设备(手机去扫描连接外设,发现外设服务和属性,操作服务和属性的应用。一般来说,外设(蓝牙设备,比如智能手环之类的东西), 会由硬件工程师开发好,并定义好设备提供的服务,每个服务对于的特征,每个特征的属性(只读,只写,通知等等),本文例子的业务场景,就是用一手机app去读写蓝牙设备。

( 1 ) 建立中心角色

( 2 ) 扫描外设(scan)

( 3 ) 链接外设 (connect)

( 4 ) 获取外设中的服务和特征

获取外设的server

获取外设的characteristic,获取characteristic的Description值

( 5 ) 与外设做数据交互

( 6 ) 订阅 characteristic 通知

( 7 ) 断开链接(disconnect)

2、外设模式流程

( 1 ) 启动 Peripheral 管理对象

( 2 ) 设置 Peripheral的 服务、特征、描述、权限

( 3 ) 设置处理订阅、取消订阅、读写characteristic(特征)委托方法

3、工作状态

( 1 ) 准备

( 2 ) 广播

( 3 ) 监听扫描

( 4 ) 发起连接

( 5 ) 已经连接

四、Center模式代码解析

1、准备工作

导入
#import <CoreBluetooth/CoreBluetooth.h>
,声明系统蓝牙设备管理者和保存外设动态数组,遵循代理
<CBCentralManagerDelegate,CBPeripheralDelegate>
,当连接外设成功后,不仅要保留外设,而且之后要与外设交互,就必须也遵循外设的一些代理方法,并设置外设对象的代理对象。

//系统狼牙设备管理者
CBCentralManager *manager;
// 用于保存被发现的设备(外设)
NSMutableArray *peripherals;


2、建立中心角色,并监听蓝牙设备状态,扫描外设

/*
*   1和2和3、建立角色中心,并确定蓝牙打开状态下,扫描外设
*    注意一个细节:  请特别注意,扫描到目标外设一定要保存!
*                如果不保存,会影响到后面的方法执行,
*                 导致无法连接和对外设后续的操作。
*
*/


- (void)viewDidLoad
{
[super viewDidLoad];

self.title = @"4.0  BLE ";

//初始化,并设置委托和线程队列
manager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
}//视图加载


查看作为center 的蓝牙的状态,并当蓝牙打开的时候,扫描外设

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{

switch (central.state) {

case CBCentralManagerStateUnknown:

break;

case CBCentralManagerStateResetting:

break;

case CBCentralManagerStateUnsupported:

break;

case CBCentralManagerStateUnauthorized:

break;

case CBCentralManagerStatePoweredOff:

NSLog(@"蓝牙关闭");

break;

case CBCentralManagerStatePoweredOn:

NSLog(@"蓝牙打开");

//扫描外设备(第一个参数为nil就是扫描所有的设备)
[manager scanForPeripheralsWithServices:nil options:nil];

break;

default:

break;
}

}//蓝牙状态


以下方法,分别是扫描外设,并连接外设成功、失败、外设断开连接的代理方法

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{

NSLog(@"发现附近蓝牙:%@---%@",peripheral.name,peripheral.identifier);

if ([peripheral.name hasPrefix:@"C"]) {

/*
找到设备,并持有他,否则CBCentralManager不会保存peripheral,
那么CBPeripheralDelegate中的代理方法也不会被调用
*/
[peripherals addObject:peripheral];

/*
一个主设别最多链接7个外设,每个外设最多只能给一个主设链接
链接成功、失败、断开就会进入各自的委托
*/

//链接设备
[manager connectPeripheral:peripheral options:nil];

}
}//扫描到设备并过滤外设,进而建立连接


- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"链接外设%@成功",peripheral.name);

// 设置外设代理
[peripheral setDelegate:self];

// 扫描外设的 services
[peripheral discoverServices:nil];

}// 与外设链接成功


-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@">>>连接到名称为(%@)的设备-失败,原因:%@",[peripheral name],[error localizedDescription]);
}//链接失败


- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@">>>外设连接断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);

}// 外设断开连接


3、当连接成功,扫描外设的服务和特征(也就是遵循外设的几个代理方法)

/*
设备连接成功后,就可以扫描设备的服务了,同样是通过委托形式,扫描到结果后会进入委托方法。但是这个委托已经不再是主设备的委托(CBCentralManagerDelegate),而是外设的委托(CBPeripheralDelegate),这个委托包含了主设备与外设交互的许多 回叫方法,包括获取services,获取characteristics,获取characteristics的值,获取characteristics的Descriptor,和Descriptor的值,写数据,读rssi,用通知的方式订阅数据等等

*/


pragma mark - Peripheral 代理方法

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{

NSLog(@">>>扫描到服务:%@",peripheral.services);

if (error) {

NSLog(@"%@",[error localizedDescription]);
return;
}

for (CBService *service in peripheral.services) {

/*
* 扫描每个服务的 service  进而获取 characteristics 调用下面的代理方法
*
*   -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
*/

[peripheral discoverCharacteristics:nil forService:service];

}

}//扫描到服务

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error) {

NSLog(@"%@",[error localizedDescription]);
}

/*
*    读取Characteristic 的值
*     进入下面代理方法
*   - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
*
*/
for (CBCharacteristic *Characteristic in service.characteristics) {

//NSLog(@"%@----%@",service.UUID,Characteristic.UUID);
[peripheral readValueForCharacteristic:Characteristic];
}

/*
*  读取 Characteristic 的 Descriptors
*
*/

for (CBCharacteristic *Characteristic in service.characteristics) {

[peripheral discoverDescriptorsForCharacteristic:Characteristic];
}

}//每个服务的特征值

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

// characteristic 的value值是NSData
NSLog(@"%@",characteristic.value);

}//获取的charateristic的值

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
for (CBDescriptor *des in characteristic.descriptors) {

NSLog(@"%@",des.UUID);
}

}//搜索到Characteristic的Descriptors

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

//这个descriptor都是对于characteristic的描述,一般都是字符串,所以这里我们转换成字符串去解析
NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);

}//获取 Descriptors的值


5、与外设进行交互(UE)

-(void)writeCharacteristic:(CBPeripheral *)peripheral
characteristic:(CBCharacteristic *)characteristic
value:(NSData *)value
{

//打印出 characteristic 的权限,可以看到有很多种,这是一个NS_OPTIONS,就是可以同时用于好几个值,常见的有read,write,notify,indicate,知知道这几个基本就够用了,前连个是读写权限,后两个都是通知,两种不同的通知方式。
/*
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
};

*/
NSLog(@"%lu", (unsigned long)characteristic.properties);

//只有 characteristic.properties 有write的权限才可以写
if(characteristic.properties & CBCharacteristicPropertyWrite){
/*
最好一个type参数可以为CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,区别是是否会有反馈
*/
[peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}else{

NSLog(@"该字段不可写!");
}

}//写数据


6、订阅Characteristic通知(订阅和取消)

-(void)notifyCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic
{

//设置通知,数据通知会进入:didUpdateValueForCharacteristic方法
[peripheral setNotifyValue:YES forCharacteristic:characteristic];

}//设置通知

-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic
{

[peripheral setNotifyValue:NO forCharacteristic:characteristic];

}//取消通知


7、与外设断开连接

-(void)disconnectPeripheral:(CBCentralManager *)centralManager peripheral:(CBPeripheral *)peripheral
{

//停止扫描
[centralManager stopScan];

//断开连接
[centralManager cancelPeripheralConnection:peripheral];

}// 停止扫描和断开连接


提醒 : 关于 4.0BLE,github有人专门进行了二次封装,可通过cocoapods进行下载

pod 'BabyBluetooth','~> 0.6.0'

开发导入 #import "BabyBluetooth.h"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: