美文网首页
iOS BLE开发

iOS BLE开发

作者: 起个名字想破头 | 来源:发表于2018-10-09 20:31 被阅读15次

    简介

    BLE(Bluetooth Low Energy),低功耗蓝牙,使用2.4GHz无线电频率。从蓝牙4.0开始支持。通常我们的手机都已支持蓝牙4.0,iPhone从iPhone4s起已经支持蓝牙4.0(不是iPhone4s就是iPhone5,具体没仔细查),而从iPhone8开始,蓝牙已经使用5.0了,可以支持蓝牙mesh。

    宣告与发现

    BLE设备通过广播宣告(advertising)数据包的方式被发现,发现设备的等待时间存在概率性,取决于三个参数(宣告间隔、扫描间隔和扫描窗口)。对于iOS开发,并不需要关心这几个参数,系统底层已经为我们做了最佳的选择。

    通信

    蓝牙技术联盟沿用经典蓝牙的规范内容,为蓝牙低功耗定义了一些profile,这些profile定义了一个设备在特定应用情景下如何工作。profile都基于通用属性规范(GATT)。GATT定义了属性,作为通用的封装数据的单位,并定义了如何通过蓝牙连接传输属性从而达到传输数据的目的。
    对于手机端来说,蓝牙设备的数据简单来说就是一堆UUID及其对应的值,iOS就是一堆CBUUID。

    Exp:

    将一个WiFi+BLE设备接入家庭WiFi,共分几步:

    1. 发现设备
    2. 获取设备信息,即获取设备的services和characters
    3. 连接设备
    4. 与设备交互信息
    5. 断开连接
    • 发现设备

    //在你需要的地方初始化
    //这里创建了一个串行队列,如果queue为nil,则使用主线程
    //实际使用时globle_queue也没出现过问题
    self.serial_queue = dispatch_queue_create("ble_queue", DISPATCH_QUEUE_SERIAL);
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:self.serial_queue options:nil];
    
    //开始扫描
    /* warn:扫描接口要在下面回调中调用,而不是初始化之后就可以调用。
    在初始化之后立刻调用的话,由于当前central.state == CBManagerStateUnknown,会导致扫描失败
    */
    //实现CBCentralManagerDelegate
    - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
        if (central.state == CBManagerStatePoweredOn) {
            //在这里启动扫描接口,nil表示获取所有services
            /*CBCentralManagerScanOptionAllowDuplicatesKey 
              YES表示只要收到一个BLE设备的广播包就会上报,不会对相同的BLE设备进行过滤,这样做是比较耗电的,但业务需求,要不断更新周围的BLE设备,所以这里还是选择了YES
              NO为默认值,同一个BLE设备的广播包会被合并成,只通知一次事件
            */
            [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)}];
        }    
    }
    
    //扫描到外围设备时回调此方法
    //外围设备:建立连接过程中接受建立一个活跃的物理连接请求的LE设备定义为Peripheral 角色
    //中心设备:建立连接过程中发起建立活跃物理连接请求的LE 设备定义为Central 角色
    //在我们这个例子中手机就是中心设备,要接入家庭WiFi的这个设备就是外围设备
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
        //在该方法中,可以通过advertisementData解析过滤出自己的设备
        //RSSI为信号强度,负数,值越大(越接近0),信号越好
    
        //找到自己要连接的设备后,可以将peripheral存起来,用于后面在某个点击事件中进行连接
    }
    
    • 连接设备

    //property getter
    //我们只获取下面两个services
    - (NSArray<CBUUID *> *)serviceUUIDs {
        if (_serviceUUIDs == nil) {
            //这里遇到过一个偶现的奇葩问题
            //128bit初始化uuid时偶现过崩溃,原因未知,所以使用16bit初始化
            CBUUID* uuid1 = [CBUUID UUIDWithString:@"FF00"];
            CBUUID* uuid2 = [CBUUID UUIDWithString:@"FF10"];
            _serviceUUIDs = @[uuid1, uuid2];
        }
        return _serviceUUIDs;
    }
    
    //在你合适的地方调用连接外围设备
    self.centralManager connectPeripheral:self.peripheral options:nil];
    
    //实现CBCentralManagerDelegate
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
        //获取感兴趣的服务及属性
        [peripheral discoverServices:self.serviceUUIDs];
    }
    
    
    //实现CBPeripheralDelegate
    //发现所有你要的服务后会回调该方法
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error {
        //获取该属性对应的服务
        for (int i = 0; i < peripheral.services.count; i++) {
            CBService *service = peripheral.services[i];
            [peripheral discoverCharacteristics:nil forService:service];
        }
    }
    
    //发现该服务对应的属性时会回调该方法
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
        //这里我是做了个标记为,当获取到了所有我想要的属性之后,再开始读写操作
        //但这里对我是不方便的,业务需要我全部获取完之后才能读写,所以不能每次回调进来都进行相应的操作
    
        if(discoverEnd) {
            //这里就可以按照自己的协议进行读写了
            ...write(ssid+password)
            ...
        }
    }
    
    • 读写设备

    //实现相应的delegate
    //读回调
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
        //这里有一点比较奇怪的是,我对某一属性setNotifyValue
        //只有第一次是通过didUpdateNotificationStateForCharacteristic这个回调上来的
        //而其他时候都是通过读回调上来的
    
        //ooxxoo
        //在通信完成后断开设备连接
        self.centralManager cancelPeripheralConnection:peripheral];
    }
    
    //通知回调
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    
    }
    
    
    - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    
    
    }
    

    相关文章

      网友评论

          本文标题:iOS BLE开发

          本文链接:https://www.haomeiwen.com/subject/upfpoftx.html