gpt4 book ai didi

ios - 如何在后台和前台使用 iOS 7.1 中的蓝牙 LE 检测附近的设备?

转载 作者:IT王子 更新时间:2023-10-29 08:11:30 24 4
gpt4 key购买 nike

我有一个应用程序需要检测附近(在蓝牙 LE 的范围内)运行相同应用程序和 iOS 7.1 的设备。我考虑了两种检测方法:

  1. 让设备充当 iBeacon 并检测范围内的 iBeacon
  2. 使用 CoreBluetooth(如 Vicinity 实现中的 here)创建一个 BLE 外设,通告并扫描外设

似乎选项 1 是不可能的,因为:

  • 当应用程序在后台运行 (iOS 7.1) 时,iOS 可能至少需要 15 分钟才能检测到进入信标区域

选项 2 似乎可行,但在实现方面存在一些困难:

  • iOS 似乎会在一段时间后(大约 15 分钟?)更改广告数据包中的外围 UUID。这意味着无法直接从广告广播信号中识别出广告设备。

对此,我有以下疑问:

  • 是否还有其他我没有考虑过的实现附近设备检测的方法?
  • 是否可以通过广告(或其他方式)识别设备以便选项 2 起作用?

最佳答案

我找到了一个让Core Bluetooth工作的方法(选项2),过程大致如下:

  • 应用程序通过 CBAdvertisementDataLocalNameKey 中的编码设备唯一标识符为自己做广告(当广播应用程序在前台运行时)以及通过蓝牙 LE 提供设备唯一标识符的特征服务(当广播应用程序在后台运行时)
  • 与此同时,应用程序扫描其他外围设备并提供相同的服务。

广告的运作方式如下:

  • 为了让其他设备能够识别此设备,我使用每个设备唯一的 UUID(我使用 Urban Airship 的 [UAUtils deviceID],因为它是其他部分的设备标识符程序的一部分,但您也可以使用任何唯一的 ID 实现)。
  • 当应用程序在前台运行时,我可以使用 CBAdvertisementDataLocalNameKey 直接在广告数据包中传递设备唯一 ID。标准 UUID 表示太长,所以我使用 UUID 的缩写形式如下:

    + (NSString *)shortenedDeviceID
    {
    NSString *deviceID = [UAUtils deviceID];

    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:deviceID];
    uuid_t uuidBytes;
    [uuid getUUIDBytes:uuidBytes];

    NSData *data = [NSData dataWithBytes:uuidBytes length:16];
    NSString *base64 = [data base64EncodedStringWithOptions:0];
    NSString *encoded = [[[base64
    stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
    stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
    stringByReplacingOccurrencesOfString:@"=" withString:@""];
    return encoded;
    }
  • 当应用程序在后台运行时,广告数据包被剥离,CBAdvertisementDataLocalNameKey 不再传递。为此,应用程序需要发布提供唯一设备标识符的特性:

    - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
    {
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
    [self startAdvertising];

    if (peripheralManager) {
    CBUUID *serviceUUID = [CBUUID UUIDWithString:DEVICE_IDENTIFIER_SERVICE_UUID];
    CBUUID *characteristicUUID = [CBUUID UUIDWithString:DEVICE_IDENTIFIER_CHARACTERISTIC_UUID];
    CBMutableCharacteristic *characteristic =
    [[CBMutableCharacteristic alloc] initWithType:characteristicUUID
    properties:CBCharacteristicPropertyRead
    value:[[MyUtils shortenedDeviceID] dataUsingEncoding:NSUTF8StringEncoding]
    permissions:CBAttributePermissionsReadable];
    CBMutableService *service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES];
    service.characteristics = @[characteristic];
    [peripheralManager addService:service];
    }
    }
    }

扫描工作如下:

  • 您开始扫描具有特定服务 UUID 的外围设备,如下所示(注意您需要指定服务 UUID,否则后台扫描将无法找到设备):

    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:DEVICE_IDENTIFIER_SERVICE_UUID]]
    options:scanOptions];
  • 当在 发现设备时 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
    advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
    你检查 advertisementData[CBAdvertisementDataLocalNameKey] 是否存在并尝试将其转换回 UUID 形式,如下所示:

    + (NSString *)deviceIDfromShortenedDeviceID:(NSString *)shortenedDeviceID
    {
    if (!shortenedDeviceID)
    return nil;
    NSString *decoded = [[[shortenedDeviceID
    stringByReplacingOccurrencesOfString:@"_" withString:@"/"]
    stringByReplacingOccurrencesOfString:@"-" withString:@"+"]
    stringByAppendingString:@"=="];

    NSData *data = [[NSData alloc] initWithBase64EncodedString:decoded options:0];
    if (!data)
    return nil;

    NSUUID *uuid = [[NSUUID alloc] initWithUUIDBytes:[data bytes]];

    return uuid.UUIDString;
    }
  • 如果转换失败,您知道广播设备在后台,您需要连接到该设备以读取提供唯一标识符的特性 .为此,您需要使用 [self.central connectPeripheral:peripheral options:nil];(使用 peripheral.delegate = self; 并实现一系列委托(delegate)方法,如下所示:

    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
    {
    [peripheral discoverServices:@[[CBUUID UUIDWithString:DEVICE_IDENTIFIER_SERVICE_UUID]]];
    }

    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
    {
    if (!error) {
    for (CBService *service in peripheral.services) {
    if ([service.UUID.UUIDString isEqualToString:DEVICE_IDENTIFIER_SERVICE_UUID]) {
    NSLog(@"Service found with UUID: %@", service.UUID);
    [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:DEVICE_IDENTIFIER_CHARACTERISTIC_UUID]] forService:service];
    }
    }
    }
    }

    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
    {
    if (!error) {
    for (CBCharacteristic *characteristic in service.characteristics) {
    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:DEVICE_IDENTIFIER_CHARACTERISTIC_UUID]]) {
    [peripheral readValueForCharacteristic:characteristic];
    }
    }
    }
    }

    - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    {
    if (!error) {
    NSString *shortenedDeviceID = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    NSString *deviceId = [MyUtils deviceIDfromShortenedDeviceID:shortenedDeviceID];
    NSLog(@"Got device id: %@", deviceId);
    }
    }

关于ios - 如何在后台和前台使用 iOS 7.1 中的蓝牙 LE 检测附近的设备?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24352764/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com