iOS - Bluetooth蓝牙篇(BLE)

BLE ==== buletouch low energy,蓝牙4.0设备因为低耗电,所以也叫做BLE。

##一、名字术语

说到BLE 少不了这几个名词:

Service:服务,是把数据分成一个个的独立逻辑项,它包含一个或者多个 Characteristic。每个 Service 有一个 UUID 唯一标识。UUID 有 16 bit 的,或者 128 bit 的。16 bit 的 UUID 是官方通过认证的,需要花钱购买,128 bit 是自定义的,可以自己设置。每个外设会有很多服务,每个服务中包含很多字段,这些字段的权限一般分为读 read,写 write,通知 notiy几种,就是我们连接设备后具体需要操作的内容。

Characteristic:特征,GATT 事务中的最低界别,Characteristic 是最小的逻辑数据单元,当然它可能包含一个组关联的数据,例如加速度计的 X/Y/Z 三轴值。与 Service 类似,每个 Characteristic 用 16 bit 或者 128 bit 的 UUID 唯一标识。每个设备会提供服务和特征,类似于服务端的 API,但是机构不同。

Description:每个 Characteristic 可以对应一个或多个Description用户描述 Characteristic 的信息或属性。

Peripheral、Central:外设和中心,发起连接的是 Central,被连接的设备为 Peripheral。

##二、工作模式

这两组 API 分别对应不同的业务场景,如下图,左侧叫做中心模式,就是以你的手机(App)作为中心,连接其他的外设的场景。而右侧称为外设模式,使用手机作为外设连接其他中心设备操作的场景。

####一般业务中Central模式使用的多,这里我就说下Central模式的流程

蓝牙数据接收的一般流程:

1、蓝牙外设设备在不断地在广播信号;

2、建立中心角色CBCentralManager,开启扫描;

3、发现设备(根据唯一标志来辨别是不是我们要连接的设备);

4、连接(成功);

5、调用方法发现「服务」;

6、调用方法发现「服务」里的「特征」(一般通过UUID来唯一辨识某个服务);

7、发现硬件数据写入的「特征」,记录便于后面数据写入;(一般通过UUID来唯一辨识写入write特征)

8、发现硬件用于数据输出的「特征」,进行「监听」((一般通过UUID来唯一辨识notiy特征);

9、利用数据输入「特征」发送数据,或者等待数据输出「特征」发出来的数据。

##三、代码实现

1 导入头文件:

#import <CoreBluetooth/CoreBluetooth.h>

1

###2 创建初始化蓝牙设备,同时系统会回调centralManagerDidUpdateState,告诉我们手机当前蓝牙状态:

CBManager *manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

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

//    CBManagerStateUnknown = 0,状态未知,更新迫在眉睫。

//    CBManagerStateResetting,与系统服务的连接暂时丢失,即将更新。

//    CBManagerStateUnsupported,该平台不支持蓝牙低能耗中央/客户端角色。

//    CBManagerStateUnauthorized,应用程序未被授权使用蓝牙低能耗中央/客户端角色。

//    CBManagerStatePoweredOff,蓝牙目前处于关闭状态

//    CBManagerStatePoweredOn,蓝牙目前处于开机状态,可以使用。

}

1

2

3

4

5

6

7

8

9

10

###3 开始搜索外设

[manager scanForPeripheralsWithServices:nil options:nil];

在设备搜索到外设后,会回调以下方法

//这里如果你要连接唯一蓝牙设备可以通过蓝牙名字等唯一表示帅选 :

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

{

    HSLog(@"发现蓝牙设备%@--",peripheral);

    if (peripheral.name.length > 0) {

        HSLog(@"连接蓝牙名字---%@---%@",perName,peripheral);

        if ([@”小米“ isEqualToString:[peripheral.name stringByReplacingOccurrencesOfString:@" " withString:@""]])

        {

                _connectedPeripheral = peripheral; //这里记住引用该从设备,不然此方法后会报错

                [manager connectPeripheral:peripheral options:nil];

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

####这里插播一条,如何确定设备唯一标识符

在有些时候,需要获取 peripheral 的唯一标示符(比如要做自动连接或绑定用户等操作),但是在搜索到 peripheral 之后,只能拿到 identifier,而且这个 identifier 根据连接的 central 不同而不同。也就是说,不同的手机连上之后,identifier 是不同的。虽然比较坑爹,但是这并不影响你做蓝牙自动连接。

    CB_EXTERN_CLASS @interface CBPeripheral : CBPeer

    // 蓝牙设备的名称

    @property(retain, readonly, nullable) NSString *name;

    // 蓝牙设备的信号强度

    @property(retain, readonly, nullable) NSNumber *RSSI NS_DEPRECATED(NA, NA, 5_0, 8_0);

    // 蓝牙设备的连接状态,枚举值

    @property(readonly) CBPeripheralState state;

    // 蓝牙设备包含的服务

    @property(retain, readonly, nullable) NSArray<CBService *> *services;

    CB_EXTERN_CLASS @interface CBPeer : NSObject <NSCopying>

    // 蓝牙设备的 UUID 标识符

    @property(readonly, nonatomic) NSUUID *identifier NS_AVAILABLE(NA, 7_0);

唯一标示符(并且不会变的)是设备的 MAC 地址,对于 Android 来说,轻轻松松就能拿到,但对于 iOS,目前这一属性还是私有的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

如果一定有这样的需求(即一定要使用 MAC 地址),可以和硬件工程师沟通,使用下面的某一种方式解决:

将 MAC 地址写在某一个蓝牙特征中,当我们连接蓝牙设备之后,通过某一个特征获取 MAC 地址。

将 MAC 地址放在蓝牙设备的广播数据当中,然后在广播的时候,将 MAC 地址以广播的形式发出来,在不建立连接的情况下,就能拿到 MAC 地址。

我们可以通过蓝牙设备的出厂设备或者后期手动修改蓝牙设备的 name,作为唯一标识。

###4 是否连接上指定设备

#pragma mark - CBCentralManagerDelegate  连接成功

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{

    [_cbCM stopScan];

    HSLog(@"已连接到蓝牙%@",peripheral.name);

    _connectedPeripheral = peripheral;

    peripheral.delegate=self;

    [peripheral discoverServices:nil];

}

#pragma mark - CBCentralManagerDelegate  连接失败

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

    _connectedPeripheral=nil;

    [self searchBleDevices];

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

###5 开始搜索服务[peripheral discoverServices:nil];

#pragma mark - CBPeripheralDelegate  已搜索到Services

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

    for (CBService *s in peripheral.services) {

            if ([s.UUID.UUIDString isEqualToString:@"你要的服务ID"]) {

              [peripheral discoverCharacteristics:nil forService:s];//这里可以通过service的UUID属性来辨识你要的服务

      }

    }

}

1

2

3

4

5

6

7

8

###6 发现服务里的特征值[peripheral discoverCharacteristics:nil forService:s]

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

{

//(我这里得到两个特征,一个读,一个写,也有可能是读写都可以,就一个特征的)

    //开启订阅(开启监听数据)

    for (CBCharacteristic *characteristic in service.characteristics) {

            HSLog(@"%@",characteristic);

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"0003CDD2-0000-1000-8000-00805F9B0131"]]){

            self.writeCharacteristic = characteristic;

        }else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"0003CDD1-0000-1000-8000-00805F9B0131"]]){

            // 订阅, 实时接收

            [peripheral setNotifyValue:YES forCharacteristic:characteristic];

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

###7 收到蓝牙返回的数据后会调用didUpdateValueForCharacteristic

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

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"0003CDD1-0000-1000-8000-00805F9B0131"]])

    {

        NSString *hexValue =[self bytesToHex:characteristic.value];

      NSString *ASCIIValue = [[NSString alloc] initWithData:characteristic.value encoding:NSASCIIStringEncoding];

        HSLog(@"%@",[NSString stringWithFormat:@"hexValue--%@",hexValue]);

    }

}

1

2

3

4

5

6

7

8

###8 发送数据给从设备

    if ((characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse) != 0)

    {

        [[HSBleManager sharedManager].connectedDevice writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];

        characteristicWriteCompletionHandler (YES,nil);

    }else{

        [[HSBleManager sharedManager].connectedDevice writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

    };

————————————————

版权声明:本文为CSDN博主「Jon Qin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qpc2015/article/details/86630664

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

推荐阅读更多精彩内容