iOS蓝牙开发详解

iOS蓝牙开发详解

随着物联网技术的高速发展,蓝牙开发也越来越火热。不论是智能穿戴设备还是蓝牙家具,车联网蓝牙,都是通过蓝牙协议来进行通信。废话不多说了,先向大家简单的介绍有关蓝牙开发的知识。蓝牙低能耗(BLE),以下介绍的都是围绕iOS的蓝牙(4.0)框架展开的。

蓝牙开发分为中心管理者者模式和外设管理者模式:1.常用的(90%)就是使用中心管理者者模式作为开发,就是我们手机作为中心管理者,扫描、连接蓝牙外设;2.外设管理者模式,这个基本用到的比较少,我们手机自己作为外设,自己创建服务和特征,然后通过广播,把自己的信息广播出去,其他的设备可以扫描连接到我们的手机。

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

  • 广播包: (Advertising)广播包是一个公开的信息,别人不需要连接你的设备就能读取到的信息;(iOS端由于苹果的限制,无法获取设备的Mac地址,只能让硬件放于广播包中。)

  • 外设: (peripheral)一个蓝牙硬件就是一个外设,一个外设下有一个或者多个服务;

peripheral.png
  • 服务: (services)蓝牙外设对外广播的必定会有一个服务,可能也有多个,服务下面包含着一些特征值,服务可以理解成一个端口;
service.png
  • 特征: (characteristic)特征可以理解成一个HTTP的接口,一般特征都会有value,也就是特征值。每个特征都有一个或多个权限,例如读、写、通知。向一个特征写值可以看做是发起一个HTTP请求。(和HTTP请求不同的是,如果你写入的type和硬件底层的type不配套会写不进去。无论是哪个type,系统都会通过代理回调告知我们是否写入。)因此特征是与外界交互的最小单位;
characteristic.png
  • UUID:可以理解成蓝牙上的唯一标识符,为了区分不同的服务和特征,我们就用UUID来代表服务和特征。

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

  1. 建立一个Central Manager实例,实现Central代理协议进行蓝牙管理。
  2. 打开蓝牙,扫描周围外设,获取广播包数据信息。
  3. 根据广播包数据连接指定外设。(目前我测试一个APP连接7个外设是没有问题,但是一个手机能连接多少个并没有测试,如果有知道的请告诉我。)
  4. 获得外设的服务。
  5. 获得服务的特征。
  6. 从外设读数据。
  7. 给外设发送数据。
#pragma mark - 扫描、连接操作
/**
 开始搜索
*/
- (void)startScan {
    
    [self.manager scanForPeripheralsWithServices:nil options:nil];
}
/**
 开始搜索
*/
- (void)startScanWith:(didDiscoverPeripheral)block {
    
    self.didDiscoverPeripheralBlock = block;
    [self.manager scanForPeripheralsWithServices:nil options:nil];//扫描设备,可设置扫描的服务和选项。不填写可以加快扫描速度。
}
/**
 连接指定设备,可设置连接选项
*/
- (void)linkWith:(Device *)device options:(nullable NSDictionary<NSString *,id> *)dic handle:(didConnectPeripheral)block {
    
    //防止多次点击,连接多次,只让连接一个,如果做BLE4.0多连接可以取消这个限定
    if (self.linkStatus != BLEManagerUnLinked) {
        
        return;
    }
    self.linkStatus = BLEManagerLinking;
    self.didConnectPeripheralBlock = block;
    //iOS端链接外设只能用扫描到的外设,如果连接的外设为空会crash。
    if (device.per) {
        
        [self.manager connectPeripheral:device.per options:dic];
    }
    [self performSelector:@selector(linkOuttime) withObject:nil afterDelay:5];//超过五秒则认为超时,取消连接
    self.linkDevice = device;
}

/**
 连接超时
 */
- (void)linkOuttime {
    
    if (self.linkStatus != BLEManagerLinked) {
        
        [self disconnectPeripheral:self.manager peripheral:self.linkDevice.per];
        NSError *error = [NSError errorWithDomain:@"连接超时" code:1 userInfo:nil];
        self.linkStatus = BLEManagerUnLinked;
        self.didConnectPeripheralBlock(NO, error);
    }
}

//断开连接
- (void)disconnectPeripheral:(CBPeripheral *)peripheral {
    
    //断开连接 如果外设为空会crash
    if (peripheral) {
        
        [self.manager cancelPeripheralConnection:peripheral];
    } else {
        
        if (self.didDisconnectPeripheralBlock) {

            self.didDisconnectPeripheralBlock(peripheral, nil);
        }
    }
    
    [self cleanData];
}

- (void)cleanData {
    
    //数据回归初始化状态
    self.datas = [NSMutableArray array];
    self.allDevice = [@{} mutableCopy];
    self.linkStatus = BLEManagerUnLinked;
}
#pragma mark - 发送数据
/**
 发送数据

 @param data 数据
 @param type 写入类型
 */
- (void)sendData:(NSData *)data withType:(CBCharacteristicWriteType)type{
    
    //数据发送,发送的时候,外设特征值必须存在,发送的数据是NSData类型
    /*
     具体使用哪种类型,询问硬件工程师或者查看接口文档
     两者的区别在于写入的通道不同(硬件工程师和我说的),如果type不对应则会写入失败。
     type:
     type为CBCharacteristicWriteWithResponse类型时,didWriteValueForCharacteristic会返回写入调用的结果,而CBCharacteristicWriteWithoutResponse则不会。。
     
     */

    [self.send sendData:data withType:type];
}


/**
 外设的特征值更新通知
 
 @param peripheral 连接(更新)的外设
 @param characteristic 连接(更新)的外设的特征值
 @param error 错误信息
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    
    //打印出characteristic的UUID和值
    NSLog(@"characteristic.uuid = %@, value = %@",characteristic.UUID,characteristic.value);
    //!注意,value的类型是NSData,具体开发时,会根据外设协议制定的方式去解析数据
    if ([characteristic.UUID.UUIDString isEqualToString:@"readCharacteristic"]) {
        
        NSData *data = characteristic.value;
        //把读取到的数据回调出去
        for (getData block in self.getDataBlockArr) {
            
            block(data);
        }
    } else if ([characteristic.UUID.UUIDString isEqual:readCharacteristicUUID]||[characteristic.UUID.UUIDString isEqual:notiyCharacteristicUUID]||[characteristic.UUID.UUIDString isEqual:writeCharacteristicUUID]) {
        
        NSData *data = characteristic.value;
        //把读取到的数据回调出去
        for (getData block in self.getDataBlockArr) {
            
            block(data);
        }
    }
}

/**
 已经写完数据回调
 
 @param peripheral 连接(写入)的外设
 @param characteristic 连接(写入)的外设的特征值
 @param error 是否写入成功,如果error为nil则写入成功,否则error会存在
 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    
    NSLog(@"didWriteValue error = %@", error);
}

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

推荐阅读更多精彩内容