So I have an iOS app that advertises as a BLE peripheral and sees other peripherals using CBPeripheralManager and CBCentralManager, and when I'm running those samples as iOS to iOS everything works fine. I also have another app on Android that does the same thing, and Android to Android can see each other fine as well. Where this gets messy is Android can see iOS devices advertising, but iOS can't see the advertising Android device. Anyone run into this situation before? My Android advertising code looks like this:
private void advertise( String someString ) {
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported() ) {
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_BALANCED )
.setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM )
.setConnectable( false )
.build();
UUID uuid = UUID.fromString( mUUID );
ParcelUuid pUuid = new ParcelUuid( uuid );
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName( true )
.setIncludeTxPowerLevel( true )
.addServiceUuid( pUuid )
.addServiceData( pUuid, someString.getBytes( Charset.forName("UTF-8") ) )
.build();
//Using a wrapper class for the callback for backwards compatibility issues
advertiser.startAdvertising(settings, data, AdvertisingCallbackCreator.getAdvertiseCallback());
} else {
if( Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ) {
DLog.v( "Device requires Lollipop or higher to broadcast over bluetooth" );
} else {
DLog.v( "Device must support multiple advertising in order to broadcast over bluetooth. http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#isMultipleAdvertisementSupported() ");
}
}
}
My iOS apps are fairly simple, one target is a scanner and the other is an advertiser. The scanner that's having problems viewing Android looks like this in the ViewController class:
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) CBCentralManager* pMgr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initWithUUID:nil];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)peripheral{
if (peripheral.state == CBCentralManagerStatePoweredOn) {
[self startDiscovery];
}
}
-(void)initWithUUID:(CBUUID*) uuid{
if( self ) {
_serviceUUID = uuid;
_pMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
}
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog( @"%@", advertisementData );
}
-(void) startDiscovery {
NSArray *array = @[[CBUUID UUIDWithString:@"6098FDEF-B82C-43F1-8BFB-18757743BA10"]];
[_pMgr scanForPeripheralsWithServices:array options:nil];
}
@end
My advertiser that can be seen by both Android and iOS looks like this:
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) CBPeripheralManager* pMgr;
@property (strong, nonatomic) CBMutableService* shareService;
@property (strong, nonatomic) CBMutableCharacteristic* notificationCharacteristic;
@property (strong, nonatomic) NSMutableArray *queuedWrites;
@property (strong, nonatomic) NSLock *queuedWritesLock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initWithUUID:[CBUUID UUIDWithString:@"6098FDEF-B82C-43F1-8BFB-18757743BA10"]];
[self startAdvertising];
}
-(void) initWithUUID:(CBUUID*) uuid{
if( self ) {
_serviceUUID = uuid;
_pMgr = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
self.bkvsName = [[UIDevice currentDevice] name];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) startAdvertising {
if ([_pMgr state] == CBPeripheralManagerStatePoweredOn) {
NSDictionary* adDictionary = @{ CBAdvertisementDataLocalNameKey :
[NSString stringWithFormat:@"BKV %@", _bkvsName ],
CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:@"6098FDEF-B82C-43F1-8BFB-18757743BA10"]]};
[_pMgr startAdvertising:adDictionary];
}
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
_shareService = [[CBMutableService alloc] initWithType:_serviceUUID primary:YES];
_notifyUUID = [CBUUID UUIDWithString:@"F098FDEF-B82C-43F1-8BFB-18757743BA10"];
_notificationCharacteristic = [[CBMutableCharacteristic alloc] initWithType:_notifyUUID
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
[_shareService setCharacteristics:@[_notificationCharacteristic]];
[_pMgr addService:_shareService];
[self startAdvertising];
}
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error {
if (error) {
NSLog(@"Error: %@",error);
}
}
-(void) stopAdvertising{
[_pMgr stopAdvertising];
}
@end
If anyone has some pointers on what may be wrong, that'd be awesome. I tried to keep the iOS code super simple since I'm just starting out learning it.
Edit:
Raw packet from the advertising iOS device:
2015-09-22 21:30:18.518 BLEScanner[724:42204] {
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = "BKV EV59'\U2019\U2018`s iphone ";
kCBAdvDataServiceUUIDs = (
"6098FDEF-B82C-43F1-8BFB-18757743BA10"
);
}
Also when nil is used instead of array in scanForPeripheralsWithServices, the Android device still isn't seen. The scanner does pick up another bluetooth device I have nearby that is in advertising mode (a bluetooth enabled toy, not a phone), however.
While I don't think this comes into play, the devices I'm testing with are a Nexus 9 on M Preview 3, Nexus 6 on 5.1.1, and two iPod Touches (recent models running iOS 8.3 and 8.4)