Failing To Discover Bluetooth LE Service Advertisement in iOS - ios

I have created two iOS apps; one a Bluetooth LE peripheral that advertises a service, and one a Bluetooth LE central that scans for the advertised service. The peripheral is running on my iPhone5s, and the central is running on my iPad Mini. I initially set the central up to scan for the specific advertised service, but later changed it to listen to any service. In either case, the iPad Mini app acting as a central never detects any advertised service. I am uncertain whether its a problem with the way I setup the peripheral manager to advertise, or if its a problem with the way I setup the central manager to scan, or a device configuration problem. Please offer suggestions or tests I can perform to get this working.
The following is the relevant code for the iPhone5s app acting as a peripheral:
CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
CBUUID *immediateAlertServiceUUID = [CBUUID UUIDWithString: IMMEDIATE_ALERT_SERVICE_UUID];
CBUUID *alertLevelCharacteristicUUID = [CBUUID UUIDWithString: ALERT_LEVEL_CHARACTERISTIC_UUID];
CBUUID *myCustomCharacteristicUUID = [CBUUID UUIDWithString: MY_CUSTOM_CHARACTERISTIC_UUID];
alertLevelCharacteristic =
[[CBMutableCharacteristic alloc] initWithType:alertLevelCharacteristicUUID
properties:CBCharacteristicPropertyRead
value: nil permissions:CBAttributePermissionsReadable];
myCustomCharacteristic =
[[CBMutableCharacteristic alloc] initWithType:myCustomCharacteristicUUID
properties:CBCharacteristicPropertyRead
value: nil permissions:CBAttributePermissionsReadable];
NSArray *myCharacteristics = #[alertLevelCharacteristic, myCustomCharacteristic];
// Now setup the service
myService = [[CBMutableService alloc] initWithType:immediateAlertServiceUUID primary:YES];
// Finally, associate the characteristic with the service. This is an array of characteristics
myService.characteristics = myCharacteristics;
[peripheralManager addService:myService];
... wait for user to push button to start advertising ...
// Start Advertising
[peripheralManager startAdvertising:#{ CBAdvertisementDataLocalNameKey : #"My Service",
CBAdvertisementDataServiceUUIDsKey : #[myService.UUID] }];
And here are the necessary delegate methods. NOTE: delegate method peripheralManagerDidUpdateState fires and indicates that "CoreBluetooth BLE hardware is powered on and ready" (same is true on the central side). Delegate method peripheralManager:didAddService:error fires without error (see output below). And delegate method peripheralManagerDidStartAdvertising:error fires without an error). Here is the service info printed from didAddService:
<CBMutableService: 0x17008efb0 Primary = YES, UUID = 1802, Included Services = (null), Characteristics = (
"<CBMutableCharacteristic: 0x1702c1500 UUID = 2A06, Value = (null), Properties = 0x2, Permissions = 0x1, Descriptors = (null), SubscribedCentrals = (\n)>",
"<CBMutableCharacteristic: 0x1702c15e0 UUID = 66E613B5-7225-42C6-A9C2-11FADAE62899, Value = (null), Properties = 0x2, Permissions = 0x1, Descriptors = (null), SubscribedCentrals = (\n)>")>
CBPeripheralManager Delegate Methods (sorry for all the code, just trying to be complete.):
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
// Determine the state of the peripheral
if ([peripheral state] == CBPeripheralManagerStatePoweredOff) {
NSLog(#"CoreBluetooth BLE hardware is powered off");
}
else if ([peripheral state] == CBPeripheralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
}
else if ([peripheral state] == CBPeripheralManagerStateUnauthorized) {
NSLog(#"CoreBluetooth BLE state is unauthorized");
}
else if ([peripheral state] == CBPeripheralManagerStateUnknown) {
NSLog(#"CoreBluetooth BLE state is unknown");
}
else if ([peripheral state] == CBPeripheralManagerStateUnsupported) {
NSLog(#"CoreBluetooth BLE hardware is unsupported on this platform");
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service
error:(NSError *)error {
if (error) {
NSLog(#"Error publishing service: %#", [error localizedDescription]);
return;
}
else {
NSLog(#"Hurray! Your Service has been successfully published as: %#", service);
}
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error {
if (error == nil) {
NSLog(#"Your service is now advertising");
}
else {
NSLog(#"In peripheralManagerDidStartAdvertising: Your service advertising failed with error: %#", error);
}
}
And here is the relevant central code that runs on the iPad Mini:
// Scan for all available CoreBluetooth LE devices
NSArray *services = #[[CBUUID UUIDWithString:IMMEDIATE_ALERT_SERVICE_UUID]];
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
//[centralManager scanForPeripheralsWithServices:services options:nil];
[centralManager scanForPeripheralsWithServices:nil options:nil];
self.centralManager = centralManager;
And here is one of the Central delegate methods. Except for centralManagerDidUpdateState:, none of the delegate methods fire.
// CBPeripheralDelegate - Invoked when you discover the peripheral's available services.
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(#"Did Discover Services");
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
// CBCentralManagerDelegate - This is called with the CBPeripheral class as its main input parameter. This contains most of the information there is to know about a BLE peripheral.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"Did Discover Peripheral");
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if (![localName isEqual:#"My Service"]) {
// We found the Device
[self.centralManager stopScan];
self.myPeripheral = peripheral;
peripheral.delegate = self;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
As a final note, I question whether BLE even works on my devices. I loaded a couple different iBeacon apps on the iPhone and iPad Mini to see if I can get the two devices to recognize iBeacons (one transmits, one receives), but they did not discover iBeacons either. I also tried with two iPhones. I also turned Bluetooth off then on. I also tried powering the devices off/on. Both devices are running in the foreground. Still no luck. Please help.

I'll concatenate all the comments here:
Using apps like LightBlue or BLE Utility can help you to find if your issue is on the peripheral side or central one, since you're developing both sides yourself.
Before looking for CBServices, you have to connect to a CBPeripheral.
Method that you did show before hand, and seems that it wasn't obvious.
Also, before starting a scan with the CBCentralManager you have to check its state, and it has to be CBPeripheralManagerStatePoweredOn.

Related

How to detect nearby devices with Bluetooth LE in iOS 7.1 both in background and foreground?

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:
Having the devices act as iBeacons and detect iBeacons in range
Using CoreBluetooth (like in Vicinity implementation here) to create a BLE peripheral, advertise that and scan the peripherals
It seems that the option 1 is out of the question because:
It may take at least 15 minutes for iOS to detect entering a beacon region when the application is running background (iOS 7.1)
Option 2 seems the way to go, but there are some difficulties regarding the implementation:
iOS seems to change the peripheral UUID in advertisement packets after a certain period of time (around 15 minutes?). This means that it's not directly possible to identify the advertising device from the advertisement broadcast signal.
Regarding this, I have the following questions:
Are there any other methods of implementing the nearby device detection I haven't considered?
Is it possible to identify the device through advertising (or by some other means) so that option 2 would work?
I found a way to make this work Core Bluetooth (option 2), the procedure is roughly the following:
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.
The advertising works as follows:
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;
}
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];
}
}
}
The scanning works as follows:
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];
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;
}
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);
}
}

Detecting Bluetooth Enabled iPhone devices in IOS7 in IOS

I am using Core Bluetooth Framework in my app.
I know how to scan for peripherals and getting values from it.(like Heart Rate Monitor)
But what I want is to retrieve the surrounding iPhone Devices list that supports BLE 4.0 and Bluetooth Enabled ones.
I referred below links..
Uses IOBluetooth Framework
Uses CoreBluetooth For Getting Peripherals not the Devices List
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
// I'm not sure how to make this work
NSLog (#"Discovered peripheral: %#", [peripheral name]);
[self.list addObject:peripheral.name]; // add peripheral name to foundarray
NSLog (#"UUID peripheral: %#", [peripheral UUID]);
NSLog (#"peripheral services before connected: %#", [peripheral services]);
NSLog(#"adversting data %#",[NSString stringWithFormat:#"%#",[advertisementData description]]);
NSLog(#"foundArray is %#", self.list);
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
NSLog(#"Central manager's state is updated to: %#", central);
if(central.state == CBCentralManagerStatePoweredOn)
{
//okay your good to go and can now scan
}
else
{
//Unable to use CentralManager methods so print out the central.state and find out why
}
}
I dont know whether Apple provides this or not..
Any Suggestions or Ideas will be appreciated..
Thank In Advance..
Try below code checkBluetoothAccess and requestBluetoothAccess method
- (void)checkBluetoothAccess {
if(!self.cbManager) {
self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
/*
We can ask the bluetooth manager ahead of time what the authorization status is for our bundle and take the appropriate action.
*/
CBCentralManagerState state = [self.cbManager state];
if(state == CBCentralManagerStateUnknown) {
[self alertViewWithDataClass:Bluetooth status:NSLocalizedString(#"UNKNOWN", #"")];
}
else if(state == CBCentralManagerStateUnauthorized) {
[self alertViewWithDataClass:Bluetooth status:NSLocalizedString(#"DENIED", #"")];
}
else {
[self alertViewWithDataClass:Bluetooth status:NSLocalizedString(#"GRANTED", #"")];
}
}
- (void)requestBluetoothAccess {
if(!self.cbManager) {
self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
/*
When the application requests to start scanning for bluetooth devices that is when the user is presented with a consent dialog.
*/
[self.cbManager scanForPeripheralsWithServices:nil options:nil];
}
You can only retrieve the surrounding iOS devices that support Bluetooth 4.0 if they are also advertising a specific service to identify them. You can't just see all iOS devices that are powered on and nearby. If they are advertising, you can just scan for nil and that will return the advertisement packets being seen.
Note: if you care about retrieving BLE devices currently connected from other apps, you can use the retrieveConnectedPeripheralsWithServices: method.

Couldn't Discover Peripheral in Core Bluetooth

I've iPhone app and I want to connect with bluetooth device to get Glucose Measurements. You can find the device from here.
After reading Apple documentation about Core Bluetooth I started reading these tutorial. Also I get the services ID's for bluetooth devices from these link here
So I started to code like in the tutorial after understanding the basics.
And these my Code:
#define POLARH7_HRM_DEVICE_INFO_SERVICE_UUID #"180A" // for Device Information service.
#define POLARH7_HRM_HEART_RATE_SERVICE_UUID #"1808" // For Glucose service.
NSArray *services = #[[CBUUID UUIDWithString:POLARH7_HRM_HEART_RATE_SERVICE_UUID], [CBUUID UUIDWithString:POLARH7_HRM_DEVICE_INFO_SERVICE_UUID]];
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[centralManager scanForPeripheralsWithServices:services options:nil];
self.centralManager = centralManager;
And I've implemented the delegates for CBCentralManagerDelegate and CBPeripheralDelegate
I receive a notification for centralManagerDidUpdateState
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
// Determine the state of the peripheral
if ([central state] == CBCentralManagerStatePoweredOff) {
NSLog(#"CoreBluetooth BLE hardware is powered off");
}
else if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
}
else if ([central state] == CBCentralManagerStateUnauthorized) {
NSLog(#"CoreBluetooth BLE state is unauthorized");
}
else if ([central state] == CBCentralManagerStateUnknown) {
NSLog(#"CoreBluetooth BLE state is unknown");
}
else if ([central state] == CBCentralManagerStateUnsupported) {
NSLog(#"CoreBluetooth BLE hardware is unsupported on this platform");
}
}
My NSLog logs : CoreBluetooth BLE hardware is powered on and ready.
But I did not receive a notification for central didDiscoverPeripheral.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0) {
NSLog(#"Found the heart rate monitor: %#", localName);
[self.centralManager stopScan];
self.polarH7HRMPeripheral = peripheral;
peripheral.delegate = self;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
These method is not being called.
So the central (my iPhone) couldn't discover the Peripheral which is my Glucose device.
I couldn't find the device when I search for it from Setting ->Bluetooth.
If centralManager:didDiscoverPeripheral:advertisementData:RSSI: is never called, this likely means that there is no peripheral with one of provided CBUUIDs. You could try to provide nil instead of the services-array and check if there is any peripheral available (don't do this in production mode).
OK, I think I figured out the problem after sending email to TaiDoc company they told me that these device dose not support iPhone bluetooth integration.
I tried to connect with Tom-Tom GPS watch and it's connected successfully :)
So I think the problem of the issue is a Hardware issue.

How to reconnect BLE device in background after turn off and then turn on?

I am working on a small project related to BLE. I have a requirement that I need to re-connect the device in background after manual turn off and then off bluetooth from iPhone->Settings->Bluetooth.
Just store the peripheral identifier or (UUID for < iOS 7), retrieve the peripheral, and call connect on it when the centralManager updates state to powered on.
For iOS 7:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if(central.state == CBCentralManagerStatePoweredOn)
{
NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:savedUUID];//where savedUUID is the string version of the NSUUID you've saved somewhere
NSArray *peripherals = [_cbCentralManager retrievePeripheralsWithIdentifiers:#[uuid]];
for(CBPeripheral *periph in peripherals)
{
[_cbCentralManager connectPeripheral:periph options:nil];
}
}
}
For iOS 6:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if(central.state == CBCentralManagerStatePoweredOn)
{
CFUUIDRef uuid;//the cfuuidref you've previously saved
[central retrievePeripherals:#[(id)uuid]];//now wait for the delegate callback below
}
}
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
for(CBPeripheral *periph in peripherals)
{
[_centralManager connectPeripheral:periph options:nil];
}
}
NOTE: these are just code snippets. You should also monitor CBCentralManagerStatePoweredOff (among others) and cancel all current peripheral connections when you get that update.

Run iOS 6 device as a BLE peripheral

As we know, iOS 6 support running devices (iPhone 4s and above, and new iPad) as a BLE peripheral. There is a demo in WWDC 2012 Session 705 called "advanced core bluetooth". I asked for the source code from Apple. They sent me a modified version of source code (BTLE_Transfer_Draft). Then I:
Run the app in iPhone 5 (iOS 6) in "Peripheral Mode" and start "Advertising"
Run the app in new iPad (iOS 5.1.1) in "Central Mode"
The problem is that the peripheral is never been discovered at all. So I use other testing applications including some downloaded from App Store. All failed to discover peripherals. I think the problem should be in BTLE_Transfer_Draft. Because I'm not sure whether I'm allowed to present the whole source code. So I just show the "peripheral mode" part here:
- (void)viewDidLoad {
[super viewDidLoad];
// Start up the CBPeripheralManager
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
// Opt out from any other state
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
return;
}
// We're in CBPeripheralManagerStatePoweredOn state...
NSLog(#"self.peripheralManager powered on.");
// ... so build our service.
// Start with the CBMutableCharacteristic
self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
// Then the service
CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]
primary:YES];
// Add the characteristic to the service
transferService.characteristics = #[self.transferCharacteristic];
// And add it to the peripheral manager
[self.peripheralManager addService:transferService];
}
/** Start advertising
*/
- (IBAction)switchChanged:(id)sender
{
if (self.advertisingSwitch.on) {
// All we advertise is our service's UUID
[self.peripheralManager startAdvertising:#{ CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
}
else {
[self.peripheralManager stopAdvertising];
}
}
The BLE is in powered on status and the startAdvertising is called. But the BLE central can never discover it.
Post updated:
According to mttrb's suggestion I added "CBAdvertisementDataLocalNameKey" when I startAdvertising. But my service is still can't be discovered by most of the apps including some apps from app store. The only one app can discover my service is an app from app store called "BLE scanner".
My question is: does this mean my application is working as a peripheral? But why my own code can't discover the service? How am I supposed to debug it ?
My code in Central Mode is like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Start up the CBCentralManager
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
......
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(#"Error discovering services: %#", [error localizedDescription]);
return;
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Deal with errors (if any)
if (error) {
NSLog(#"Error discovering characteristics: %#", [error localizedDescription]);
return;
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"Peripheral Disconnected");
self.discoveredPeripheral = nil;
}
The didDiscoverPeripheral and didDiscoverServices are never called. What could be wrong? Any idea? Thanks
There is also a high quality free app called LightBlue that you can use to test your code with. It should be able to pick up all devices advertising in peripheral mode and it can even turn itself into an advertising peripheral if you want to make sure your device is working properly.
I would try moving the startAdvertising: method call up and into the end of your peripheralManagerDidUpdateState: delegate method and see if that helps.
I would also add a CBAdvertisementDataLocalNameKey key-value pair to your startAdvertising: method call. I found things were unreliable when the advertisement didn't have a name.
Finally, I would invest in the BLExplr app available in the App Store to help with scanning for your peripheral. It removes the assumption that your central is working correctly.
This Git hub project also throws some light on the CBPeripheralManager API. Called PeripheralModeTest.
This line is particularly useful for setting the advertising data
NSDictionary *advertisingData = #{CBAdvertisementDataLocalNameKey : #"Device Name", CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]]};
Though I can't see any official documentation in the Apple iOS Developer Library yet. More specifically anything about setting the repeat period for the advertising.
The BTLE Transfer example has this piece of (odd) code, which may cause some troubles:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
// Reject any where the value is above reasonable range
if (RSSI.integerValue > -15) {
return;
}
// Reject if the signal strength is too low to be close enough (Close is around -22dB)
if (RSSI.integerValue < -35) {
return;
}
Just remove those two if-statements as it makes no sense!
I have made a simplified version available here that can be used to test high volumes of messages being sent from peripheral to central.
Please note that the CBPeripheralManager class was first introduced in iOS 6.0.
I do not know witch version of BTLE Central Peripheral Transfer you did actually test but current version has iOS 6 as requirement.
So I would suggest to test linkage against iOS 5.1 to see what compatibility issues it shows.

Resources