2018-02-08

                                         IOS蓝牙开发SDK通信笔记连接和读写

当下蓝牙开发可谓是越来越火,不论是智能穿戴的兴起还是蓝牙家具,车联网蓝牙等等,很多同学也会接触到蓝牙的项目,我从事蓝牙开发也有一段时间了,经手了两个项目。废话不多说了,先向大家简单的介绍有关蓝牙开发的知识。蓝牙低能耗(BLE),以下介绍的都是围绕iOS的框架展开的。

蓝牙开发分为中心者模式和管理者模式:1.常用的(其实99.99%)就是使用中心者模式作为开发,就是我们手机作为主机,连接蓝牙外设;2.管理者模式,这个基本用到的比较少,我们手机自己作为外设,自己创建服务和特征,然后有其他的设备连接我们的手机。

在做蓝牙开发之前,最好先了解一些概念:

服务(services):蓝牙外设对外广播的必定会有一个服务,可能也有多个,服务下面包含着一些特征,服务可以理解成一个模块的窗口;

特征(characteristic):存在于服务下面的,一个服务下面也可以存在多个特征,特征可以理解成具体实现功能的窗口,一般特征都会有value,也就是特征值,特征是与外界交互的最小单位;

UUID:可以理解成蓝牙上的唯一标识符(硬件上肯定不是这个意思,但是这样理解便于我们开发),为了区分不同的服务和特征,或者给服务和特征取名字,我们就用UUID来代表服务和特征。

蓝牙连接可以大致分为以下几个步骤

1.建立一个Central Manager实例进行蓝牙管理

2.搜索外围设备

3.连接外围设备

4.获得外围设备的服务

5.获得服务的特征

6.从外围设备读数据

7.给外围设备发送数据

其他:提醒

首先我们先导入系统的BLE的框架

#import

必须遵守2个协议

CBPeripheralDelegate>

/* 中心管理者 /

@property

(nonatomic, strong) CBCentralManager *cMgr;

/* 连接到的外设 /

@property

(nonatomic, strong) CBPeripheral *peripheral;

1.建立一个Central Manager实例进行蓝牙管理

-(CBCentralManager*)cmgr

{

    if (!_cmgr) {

        _cMgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];

    }

    return _cMgr;

}


//只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态

-(void)centralManagerDidUpdateState:(CBCentralManager *)central

{

    switch (central.state) {

        case 0:

           NSLog(@"CBCentralManagerStateUnknown");

            break;

        case 1:

           NSLog(@"CBCentralManagerStateResetting");

            break;

        case 2:

           NSLog(@"CBCentralManagerStateUnsupported");//不支持蓝牙

            break;

        case 3:

           NSLog(@"CBCentralManagerStateUnauthorized");

            break;

        case 4:

        {

           NSLog(@"CBCentralManagerStatePoweredOff");//蓝牙未开启

        }

            break;

        case 5:

        {

           NSLog(@"CBCentralManagerStatePoweredOn");//蓝牙已开启

              //在中心管理者成功开启后再进行一些操作

            //搜索外设

            [self.cMgrscanForPeripheralsWithServices:nil //通过某些服务筛选外设

                                              options:nil];// dict,条件

            //搜索成功之后,会调用我们找到外设的代理方法

            // -(void)centralManager:(CBCentralManager *)centraldidDiscoverPeripheral:(CBPeripheral *)peripheraladvertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外设

        }

            break;

        default:

            break;

    }

}

2.搜索外围设备 (我这里为了举例,采用了自己身边的一个手环)

//发现外设后调用的方法

-

(void)centralManager:(CBCentralManager *)central // 中心管理者

 didDiscoverPeripheral:(CBPeripheral*)peripheral //外设

     advertisementData:(NSDictionary*)advertisementData //外设携带的数据

                  RSSI:(NSNumber *)RSSI //外设发出的蓝牙信号强度

{

    //NSLog(@"%s, line = %d, cetral =%@,peripheral = %@, advertisementData = %@, RSSI = %@", __FUNCTION__,__LINE__, central, peripheral, advertisementData, RSSI);


    /*

     peripheral = , advertisementData = {

     kCBAdvDataChannel = 38;

     kCBAdvDataIsConnectable = 1;

     kCBAdvDataLocalName = OBand;

     kCBAdvDataManufacturerData = <4c69616e0e060678 a5043853 75>;

     kCBAdvDataServiceUUIDs =     (

     FEE7

     );

     kCBAdvDataTxPowerLevel = 0;

     }, RSSI = -55

     根据打印结果,我们可以得到运动手环它的名字叫OBand-75


     */


    //需要对连接到的外设进行过滤

    // 1.信号强度(40以上才连接, 80以上连接)

    // 2.通过设备名(设备字符串前缀是OBand)

    //在此时我们的过滤规则是:有OBand前缀并且信号强度大于35

    //通过打印,我们知道RSSI一般是带-的


    if ([peripheral.namehasPrefix:@"OBand"]) {

        //在此处对我们的advertisementData(外设携带的广播数据) 进行一些处理


        //通常通过过滤,我们会得到一些外设,然后将外设储存到我们的可变数组中,

        //这里由于附近只有1个运动手环, 所以我们先按1个外设进行处理


        //标记我们的外设,让他的生命周期= vc

        self.peripheral = peripheral;

        //发现完之后就是进行连接

        [self.cMgrconnectPeripheral:self.peripheral options:nil];

        NSLog(@"%s, line = %d",__FUNCTION__, __LINE__);

    }

}

3.连接外围设备

//中心管理者连接外设成功

-

(void)centralManager:(CBCentralManager *)central // 中心管理者

  didConnectPeripheral:(CBPeripheral*)peripheral //外设

{

    NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name);

    //连接成功之后,可以进行服务和特征的发现


    //  设置外设的代理

    self.peripheral.delegate = self;


    //外设发现服务,传nil代表不过滤

    //这里会触发外设的代理方法- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError*)error

    [self.peripheral discoverServices:nil];

}

//外设连接失败

-(void)centralManager:(CBCentralManager *)centraldidFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error

{

    NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);

}


//丢失连接

-(void)centralManager:(CBCentralManager *)centraldidDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error

{

    NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);

}

4.获得外围设备的服务 & 5.获得服务的特征

//发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道UUID找到你需要的特征,订阅特征,或者这里写入数据给特征也可以)

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

{

    NSLog(@"%s, line = %d",__FUNCTION__, __LINE__);


    for (CBCharacteristic *cha inservice.characteristics) {

        //NSLog(@"%s, line = %d, char =%@", __FUNCTION__, __LINE__, cha);


    }

}

6.从外围设备读数据

//更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否

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

{

    NSLog(@"%s, line = %d",__FUNCTION__, __LINE__);

    if (characteristic == @"你要的特征的UUID或者是你已经找到的特征") {

    //characteristic.value就是你要的数据

    }

}

7.给外围设备发送数据(也就是写入数据到蓝牙)

这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用啦

[self.peripheralewriteValue:_batteryData forCharacteristic:self.characteristictype:CBCharacteristicWriteWithResponse];

//第一个参数是已连接的蓝牙设备 ;第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入

//需要注意的是特征的属性是否支持写数据

-(void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)dataforCharacteristic:(nonnull CBCharacteristic *)characteristic

{

    /*

     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

     };


     打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值

     常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式

     */

//    NSLog(@"%s, line = %d, char.pro =%d", __FUNCTION__, __LINE__, characteristic.properties);

    //此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含&

}

其他:提醒

有那么多的特征,我们怎么知道哪些特征是用来读数据的,哪些是用来写入的,哪些是需要订阅之后再读的呢?

如果你们硬件工程师事先告诉你了,或者有完成的开发文档,那么就可以直接知道了,否则你就需要自己去查看特征的属性,推介可以使用下第三方的app——LightBlue,让你更能清楚的看到你蓝牙里面的服务,特征,特征的属性。

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