Ответ 1
Я нашел способ выполнить эту работу Core Bluetooth (вариант 2), процедура примерно следующая:
- Приложение объявляет себя с уникальным идентификатором кодированного устройства в
CBAdvertisementDataLocalNameKey
(когда приложение широковещания работает на переднем плане) и характеристикой, которая предоставляет уникальный идентификатор устройства через службу Bluetooth LE (когда приложение широковещательной передачи запускает фон) - В то же время приложение сканирует другие периферийные устройства с одной и той же службой.
Реклама работает следующим образом:
- Для того, чтобы другие устройства могли идентифицировать это устройство, я использую уникальный UUID для каждого устройства (я использую Urban Airship
[UAUtils deviceID]
, потому что это идентификатор устройства в других частях программы, а также - но вы также может использовать любую уникальную реализацию ID). -
Когда приложение работает на переднем плане, я могу передать уникальный идентификатор устройства непосредственно в рекламном пакете с помощью
CBAdvertisementDataLocalNameKey
. Стандартное представление 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;
и реализовать цепочку методов делегата следующим образом:- (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); } }