Detecting Bluetooth Enabled iPhone devices in IOS7 in IOS - 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.

Related

Core Bluetooth doesn't find peripherals when scanning for specific CBUUID

It seems this question was "answered" here, but without any code to show what they did differently I'm having to ask a new question.
I have my own code with the same behaviour, where scanning for specific CBUUIDs using Core Bluetooth's CBCentralManager on OS X doesn't discover an iOS device acting as a peripheral with CBPeripheralManager (unless it and its services have previously been discovered). To see if it's something wrong in my code, I downloaded Apple's sample code. Running the sample code on two iOS devices works as intended, however when copying the CBCentralManager code to an OS X app, it fails to find the iOS device.
I've uploaded an Xcode project for the OS X app, it's hosted on WikiUpload as that seems to be the least dodgy. There's also a copy on my hosting, if people prefer.
Here's the AppDelegate.m code in the OS X project also (the CoreBluetooth framework is linked in the project):
#import <CoreBluetooth/CoreBluetooth.h>
#interface AppDelegate () <CBCentralManagerDelegate, CBPeripheralDelegate>
#property (strong, nonatomic) CBCentralManager *centralManager;
#property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
#property (strong, nonatomic) NSMutableData *data;
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
#synthesize centralManager = _centralManager, discoveredPeripheral = _discoveredPeripheral, data = _data;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
// Start up the CBCentralManager
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
// And somewhere to store the incoming data
_data = [[NSMutableData alloc] init];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#pragma mark - Central Methods
/** centralManagerDidUpdateState is a required protocol method.
* Usually, you'd check for other states to make sure the current device supports LE, is powered on, etc.
* In this instance, we're just using it to wait for CBCentralManagerStatePoweredOn, which indicates
* the Central is ready to be used.
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if (central.state != CBCentralManagerStatePoweredOn) {
// In a real app, you'd deal with all the states correctly
return;
}
// The state must be CBCentralManagerStatePoweredOn...
// ... so start scanning
[self scan];
}
/** Scan for peripherals - specifically for our service's 128bit CBUUID
*/
- (void)scan
{
// This brings up nothing, unlike on iOS where it finds the device straight away
[self.centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]
options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
// [self.centralManager scanForPeripheralsWithServices:nil
// options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
NSLog(#"Scanning started");
}
/** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered.
* We check the RSSI, to make sure it's close enough that we're interested in it, and if it is,
* we start the connection process
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
//Took out RSSI check
if (self.discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
self.discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
/** If the connection fails for whatever reason, we need to deal with it.
*/
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"Failed to connect to %#. (%#)", peripheral, [error localizedDescription]);
[self cleanup];
}
/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic.
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(#"Peripheral Connected");
// Stop scanning
[self.centralManager stopScan];
NSLog(#"Scanning stopped");
// Clear the data that we may already have
[self.data setLength:0];
// Make sure we get the discovery callbacks
peripheral.delegate = self;
// Search only for services that match our UUID
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}
/** The Transfer Service was discovered
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(#"Error discovering services: %#", [error localizedDescription]);
[self cleanup];
return;
}
// Discover the characteristic we want...
// Loop through the newly filled peripheral.services array, just in case there's more than one.
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
}
/** The Transfer characteristic was discovered.
* Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Deal with errors (if any)
if (error) {
NSLog(#"Error discovering characteristics: %#", [error localizedDescription]);
[self cleanup];
return;
}
// Again, we loop through the array, just in case.
for (CBCharacteristic *characteristic in service.characteristics) {
// And check if it's the right one
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
// If it is, subscribe to it
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
// Once this is complete, we just need to wait for the data to come in.
}
/** This callback lets us know more data has arrived via notification on the characteristic
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(#"Error discovering characteristics: %#", [error localizedDescription]);
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringFromData isEqualToString:#"EOM"]) {
// We have, so show the data,
//[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
NSLog(#"Text: %#", [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]);
// Cancel our subscription to the characteristic
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
// and disconnect from the peripehral
[self.centralManager cancelPeripheralConnection:peripheral];
}
// Otherwise, just add the data on to what we already have
[self.data appendData:characteristic.value];
// Log it
NSLog(#"Received: %#", stringFromData);
}
/** The peripheral letting us know whether our subscribe/unsubscribe happened or not
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(#"Error changing notification state: %#", error.localizedDescription);
}
// Exit if it's not the transfer characteristic
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
return;
}
// Notification has started
if (characteristic.isNotifying) {
NSLog(#"Notification began on %#", characteristic);
}
// Notification has stopped
else {
// so disconnect from the peripheral
NSLog(#"Notification stopped on %#. Disconnecting", characteristic);
[self.centralManager cancelPeripheralConnection:peripheral];
}
}
/** Once the disconnection happens, we need to clean up our local copy of the peripheral
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"Peripheral Disconnected");
self.discoveredPeripheral = nil;
// We're disconnected, so start scanning again
[self scan];
}
/** Call this when things either go wrong, or you're done with the connection.
* This cancels any subscriptions if there are any, or straight disconnects if not.
* (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
- (void)cleanup
{
// Don't do anything if we're not connected
if (!self.discoveredPeripheral.isConnected) {
return;
}
// See if we are subscribed to a characteristic on the peripheral
if (self.discoveredPeripheral.services != nil) {
for (CBService *service in self.discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
if (characteristic.isNotifying) {
// It is notifying, so unsubscribe
[self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
// And we're done.
return;
}
}
}
}
}
}
// If we've got this far, we're connected, but we're not subscribed, so we just disconnect
[self.centralManager cancelPeripheralConnection:self.discoveredPeripheral];
}
And in AppDelegate.h there's the UUID definitions:
#ifndef LE_Transfer_TransferService_h
#define LE_Transfer_TransferService_h
#define TRANSFER_SERVICE_UUID #"E20A39F4-73F5-4BC4-A12F-17D1AD07A961"
#define TRANSFER_CHARACTERISTIC_UUID #"08590F7E-DB05-467E-8757-72F6FAEB13D4"
#endif
What's the problem here? According to the above linked question the service has to be part of the advertising packet, but as far as I can see that's exactly what the iOS peripheral is doing with
[self.peripheralManager startAdvertising:#{ CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
CoreBluetooth can be very frustrating. Here are a couple things to try:
#1: A peripheral that has been connected to stops advertising. If you make a successful connection to the peripheral, you'll need to restart advertising.
#2: iOS caches discovered status and provided services. There's no programmatic way to refresh / clear the cache. Try disabling BT on the iOS device and on the Mac and re-enabling it. Then attempt another connection.
#3: There's a problem with your UUIDs. Try scanning for peripherals with the UUID parameter set to nil. You should then discover all peripherals in range.
#4: The BT connection on a Mac can be finicky if the Wifi is on. Try disabling Wifi on your Mac and try again. I've found BTLE completely unusable with Wifi enabled so I've had to use ethernet when doing any BTLE dev on my MacBook.

Failing To Discover Bluetooth LE Service Advertisement in 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.

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