如何检测在背景和前景与蓝牙L​​E附近设备在IOS 7.1两者? [英] How to detect nearby devices with Bluetooth LE in iOS 7.1 both in background and foreground?

查看:429
本文介绍了如何检测在背景和前景与蓝牙L​​E附近设备在IOS 7.1两者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an app that needs to detect a nearby (in range for Bluetooth LE) devices running the same application and iOS 7.1. I've considered two alternatives for the detection:


  1. 具有设备充当iBeacons和检测范围iBeacons

  2. (在近处实施喜欢这里)使用CoreBluetooth创建BLE外设,通告和扫描外设

  1. Having the devices act as iBeacons and detect iBeacons in range
  2. Using CoreBluetooth (like in Vicinity implementation here) to create a BLE peripheral, advertise that and scan the peripherals

如此看来,选项1是出了问题,原因如下:

It seems that the option 1 is out of the question because:


  • 这可能需要至少15分钟,适用于iOS检测应用程序运行时,后台进入灯塔区(iOS版7.1)

选项2似乎要走的路,但有关于实施一些困难:

Option 2 seems the way to go, but there are some difficulties regarding the implementation:


  • 的iOS似乎在一定的时间段后更改通告报文外围UUID(约15分钟?)。这意味着它不能直接从广告广播信号识别广告装置。

对此,我有以下问题:


  • 有没有我还没有考虑贯彻附近的设备检测的任何其他方法?

  • 是否有可能通过广告(或通过其他方式),以确定设备,以便选择2将工作?

推荐答案

我找到了一种方法,使这项工作的核心蓝牙(选项2),程序大致如下:

I found a way to make this work Core Bluetooth (option 2), the procedure is roughly the following:


  • 应用程序的公布其自身的有连接codeD设备唯一的 CBAdvertisementDataLocalNameKey 标识符(当广播应用程序运行前景)和特征通过蓝牙LE服务提供了设备唯一标识符(当广播应用程序运行背景)

  • 在同一时间,应用程序的扫描其它外设的使用相同的服务。

  • The application advertises itself with an encoded device unique identifier in CBAdvertisementDataLocalNameKey (when the broadcasting application runs foreground) and a characteristic that provides the device unique identifier through a Bluetooth LE service (when the broadcasting application runs background)
  • At the same time, the application scans other peripherals with the same service.

广告作品如下:


  • 对于要能够识别该设备的其他设备,我使用的是每台设备的唯一的UUID(我使用的是城市飞艇的 [UAUtils设备ID] ,因为它是在节目的其他部分,同时也是设备标识符 - 但你还不如用任何唯一ID的实现)

  • 在应用程序运行的前景,我可以通过该装置唯一ID的直接通过广告包 CBAdvertisementDataLocalNameKey 。标准的UUID重新presentation太长,所以我用的UUID的缩写形式如下:

  • For the other devices to be able to identify this device, I use a per-device unique UUID (I'm using Urban Airship's [UAUtils deviceID], because it's the device identifier in other parts of the program, also - but you might as well use any unique ID implementation).
  • When the application is running foreground, I can pass the device unique ID directly in the advertisement packet by using CBAdvertisementDataLocalNameKey. The standard UUID representation is too long, so I use a shortened form of the UUID as follows:

+ (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 不是一起传送了。为此,应用程序需要发布的特性的,提供了唯一的设备标识符:

  • When the application is running background, the advertisement packet gets stripped and CBAdvertisementDataLocalNameKey is not passed along anymore. For this, the application needs to publish a characteristic that provides the unique device identifier:

    - (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,否则后台扫描未能找到设备):

    • You start to scan peripherals with the certain service UUID as follows (notice that you need to specify the service UUID, because otherwise background scan fails to find the device):

    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:DEVICE_IDENTIFIER_SERVICE_UUID]]
        options:scanOptions];
    


  • 当设备是在发现 - (无效)centralManager:(CBCentralManager *)中央didDiscoverPeripheral:(CBPeripheral *)外设
     advertisementData:(NSDictionary的*)advertisementData RSSI(NSNumber的*)RSSI
    您检查,如果 advertisementData [CBAdvertisementDataLocalNameKey] 存在,并试图回到将其转换UUID的形式是这样的:

  • When a device is discovered at - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI you check that if advertisementData[CBAdvertisementDataLocalNameKey] exists and try to convert it back to UUID form like this:

    + (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.delegate =自我; 和实施的委托方法链条如下:

  • If the conversion fails you know the broadcasting device is in background, and you need to connect to the device to read the characteristic that provides the unique identifier. For this you need to use [self.central connectPeripheral:peripheral options:nil]; (with peripheral.delegate = self; and implement a chain of delegate methods as follows:

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


  • 这篇关于如何检测在背景和前景与蓝牙L​​E附近设备在IOS 7.1两者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆