iOS 蓝牙4.0开发(CoreBlueTooth)

一、蓝牙开发引入

情景 : 蓝牙(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"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值