我有一个应用需要检测运行相同应用程序和iOS 7.1的附近(蓝牙LE范围内)设备。我已经考虑了两种检测方法:
似乎选项1是不可能的,因为:
选项2似乎还有待实施,但实施方面存在一些困难:
关于这一点,我有以下问题:
答案 0 :(得分:20)
我找到了一种方法让这项工作成为Core Bluetooth(选项2),程序大致如下:
CBAdvertisementDataLocalNameKey
中的编码设备唯一标识符(当广播应用程序运行前景时)和通过蓝牙LE服务提供设备唯一标识符的特征(<广播应用程序运行背景)广告的工作原理如下:
[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;
并实现一系列委托方法,如下所示:
- (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);
}
}