iOS蓝牙开发详解

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

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

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

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

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

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

  • 特征: (characteristic)特征可以理解成一个HTTP的接口,一般特征都会有value,也就是特征值。每个特征都有一个或多个权限,例如读、写、通知。向一个特征写值可以看做是发起一个HTTP请求。(和HTTP请求不同的是,如果你写入的type和硬件底层的type不配套会写不进去。无论是哪个type,系统都会通过代理回调告知我们是否写入。)因此特征是与外界交互的最小单位;

  • 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);
}

复制代码

转载于:https://juejin.im/post/5a3143815188254dd936670d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值