0
votes

I am building an application where two iOS devices both transmit and scan (peripheral and central) for each other. Due to Apple's implementation, when the app is backgrounded, all identifiable information is removed from the advertising packet, meaning I need to connect to the discovered peripherals to find out who and what they are if they are transmitting in the background.

All I really need to do is identify the peripheral. (Connect and disconnect). Currently, the only way I can find to do this is to set a static characteristic attached to a common service that allows each device to uniquely identify itself, even when backgrounded. This value will not change or get updated. If I could simply look at peripheral.UUID after connecting, this would do the trick. But I can't anymore with iOS8. So, I create a characteristic to contain the unique identifier.

(Not sure if this is the best way, but its the only way I can think of.)

Everything is working great (discovering characteristic) but I am unable to retrieve anything other than nil for the characteristic, even though I have specifically set it when I started transmitting.

Here is my (Peripheral code):

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {

    // Opt out from any other state
    if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
        return;
    }
    NSLog(@"BT Transmitter Powered On");

    NSString* uniqueString = @“foobar";
    NSData* characteristicValue = [uniqueString dataUsingEncoding:NSUTF8StringEncoding];

    self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"08590F7E-DB05-467E-8757-72F6FAEB13D4"]
                    properties:CBCharacteristicPropertyRead
                    value:characteristicValue
                    permissions:CBAttributePermissionsReadable];

    CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"E20A39F4-73F5-4BC4-A12F-17D1AD07A961"] primary:YES];

    transferService.characteristics = @[self.transferCharacteristic];       
    [self.peripheralManager addService:transferService];

    [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey: @[[CBUUID UUIDWithString:@"E20A39F4-73F5-4BC4-A12F-17D1AD07A961"]] }];
}

And here is my Central Code:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        return;
    }
    for (CBCharacteristic *characteristic in service.characteristics) {
        // print out value of discovered characteristic
        NSLog (@"Characteristic discovered: %@", characteristic);  // this outputs all all the properties of the characteristic, including a value of "null".
        NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
        NSLog(@"Value: %@",value); // this prints out nothing
    }
}

What am I doing wrong? I would expect to see the value of the characteristic as "foobar" when transformed back into an NSString. Instead it is null.

2

2 Answers

2
votes

Having discovered the characteristic you need to perform a read request to actually get its value -

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        return;
    }
    for (CBCharacteristic *characteristic in service.characteristics) {
        // print out value of discovered characteristic
        NSLog (@"Characteristic discovered: %@", characteristic);  // this outputs all all the properties of the characteristic, including a value of "null".
        if ([characteristic.UUID.UUIDString isEqualToString:@"08590F7E-DB05-467E-8757-72F6FAEB13D4"]) {
            [peripheral readValueForCharacteristic:characteristic];
        NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
        NSLog(@"Value: %@",value); // this prints out nothing
    }
}

You will subsequently get a call to didUpdateValueForCharacteristic: -

-(void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    if (error == nil) {
       NSString *valueString=[[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
       NSLog(@"The value=%@",valueString
    }
}
0
votes

Update: to find the RSSI of the peripheral once you have connected to it and read its service, use the readRSSI method.

Then, strangely enough, even though its not in the documentation, this is the only delegate callback method (with RSSI) that works for me running 8.1.1.

-(void) peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error { NSLog(@"Got RSSI update in didReadRSSI : %4.1f", [RSSI doubleValue]); }

Now I just have to figure out how to link this RSSI signal with the specific peripheral I connected to and identified in the previous call.