|
Bluetooth and iOS – Use Bluetooth in your iPhone appsBy Radu Motisan Posted on July 16th, 2012 , 17527 Views (Rate 57.28) |
Introduction
![]() |
My past few articles on Bluetooth and Android , came with some sample source codes to provide an easier start for those interested in this wireless technology. Now I'm surprised to see that another successful mobile OS - Apple's iOS - has the same never-ending issues when it comes to a simple development task - writing a bluetooth application. Starting with iOS development was easy and straight-forward, but Bluetooth seems to be a no can do. Is it really? The purpose is to control the Bluetooth Radio: on, off , set it in discoverable mode, discover nearby devices, and establish a RFCOMM connection. Ideally we would also want access to L2CAP and SDP, but for a start let's take it slow. |
Evaluating the available options
Here's a list with possible approaches one should consider when wanting to write a BLuetooth application for iPhone. The list is sorted having the better/official choice in mind. Workarounds get to the bottom of the list:
1. Enroll in the made for iPhone/iPod/iPad (MFI) program. Details on costs are not available, but this is not for the small development companies, barely selling a few licenses. Some sources indicate costs depending on project, and starting numbers somewhere at 10K USD.
Not really an option IMO, as the costs involved and trouble getting certified are ridiculously high, for something so basic and simple such as building a Bluetooth application.
2. CoreBluetooth framework, currently usable only with Low Energy Bluetooth 4 devices. Since these are not largely spread this is not really an option. You won't be able to connect to standard headsets, keyboards, or other non-Bluetooth 4 devices. Also at the moment of speaking, the iPhone 4S is the only device capable of LE Bluetooth functionality. Again, not an option.
3. GameKit framework, this allows some basic Bluetooth functionality, such as finding nearby devices and establishing a serial communication link, but it only intended for use between iOS devices. So Android plus iPhone via GameKit is a no go. Remember to thank Apple for making it this way. Or not.
4. Private APIs. There is a BluetoothManager framework, in the private APIs, inside the SDK. This can be used to achieve the proposed task, but you won't get your App approved on Appstore, as private API's is not allowed by Apple. Since this is so convenient, and working so nice, almost like the real thing Apple didn't want to include, I will be using it for this article.
5. Jailbreaking and using Ringwald's BTStack. Jailbreaking = rooting = freedom, probably the best way to go . But this places you so far away from Apple's guidelines, and the Appstore itself. So better decide what your project is all about, and who your users will be.
iOS BluetoothManager Framework
Installing the Header files
Get the 4 .h files from here or here.
Browse to your Xcode installation at:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/PrivateFrameworks/BluetoothManager.framework
Create a new folder, "Headers", and copy the 4 .h files there:

Adding the new Framework in Xcode
Go to Xcode, click the project in the Navigator, and select "Build Phases". Under "Link binary with Libraries", press the Plus symbol. Select BluetoothManager.framework and click Add.


Using BluetoothManager.framework
In your
viewDidLoad
do the following:
1. get an handler to and instance of the BluetoothManager service:
// setup bluetooth interface btManager = [BluetoothManager sharedInstance];
2. register for notifications, for Bluetooth radio change (on/off) and for discovering a new device:
// setup bluetooth notifications addObserver:self selector:@selector(deviceDiscovered:) name:@"BluetoothDeviceDiscoveredNotification" object:nil]; addObserver:self selector:@selector(bluetoothAvailabilityChanged:) name:@"BluetoothAvailabilityChangedNotification" object:nil];
3. Not needed for the purpose of this app, but it really helped me during development, you can set a notification Observer, and get all system notifications, including the Bluetooth notifications or other unknown notifications. You can later register them as shown at step 2).
// global notification explorer CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, MyCallBack, NULL, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
And the callback function is a simple debug logger, outside viewDidLoad:
// global notification callback void MyCallBack (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { NSLog(@"CFN Name:%@ Data:%@", name, userInfo); }
As I said, this is an extremely useful piece of code.
4. Set the callback for the notifications registered at step 2):
/* Bluetooth notifications */ NSLog(@"NOTIFICATION:bluetoothAvailabilityChanged called. BT State: %d", [btManager enabled]); }
And here is the second one, for discovering devices nearby:
BluetoothDevice *bt = [notification object]; NSLog(@"NOTIFICATION:deviceDiscovered: %@ %@",bt.name, bt.address); //create a new list item BTListDevItem *item = [[BTListDevItem alloc] initWithName:bt.name description:bt.address type:0 btdev:bt]; //add it to list [tempArray addObject:(item)]; btDevItems = tempArray; [myTableView reloadData]; }
As you can see, the incoming notification itself is a newly discovered device, sent in the form of a BluetoothDevice object. To get it correctly I've used :
BluetoothDevice *bt = [notification object];
We store the name, the bluetooth address and the pointer to the BluetoothDevice object for later use. The name and address is used to populate the list view:

5. Turn bluetooth on / off . This is easy: we have two buttons, pressing them results in calling one of the following methods:
/* Interface actions - bt on */ - (IBAction)bluetoothON { NSLog(@"bluetoothON called."); [btManager setPowered:YES]; [btManager setEnabled:YES]; } /* Interface actions - bt off */ - (IBAction)bluetoothOFF { NSLog(@"bluetoothOFF called."); //BluetoothManager *manager = [BluetoothManager sharedInstance]; [btManager setEnabled:NO]; [btManager setPowered:NO]; }
6. Triggering bluetooth discovery. I do not enable searching for nearby bluetooth devices by default. Instead, I've added a Scan Button. The logic behind it is as following: check the bluetooth state , if on, start looking for nearby devices (resulting in device found notifications), if bluetooth is off, just throw an error message to inform the user:
/* Interface actions - scan */ - (IBAction)scanButtonAction { if ([btManager enabled]) { // clear listview [self clearAllList]; // start scan [btManager setDeviceScanningEnabled:YES]; } else { showMessage(@"Error", @"Turn Bluetooth on first!"); } }
7. Establishing a connection
There are two approaches here:
7A. Use BluetoothManager's "connectDevice" method (see BluetoothManager.h) . This method taken a single parameter, a string representing the bluetooth address we need to connect to. For some reason this only worked partially, so I abandoned this method in favor of:
7B. Use BluetoothDevice's "connect" . Remember when we saved a pointer to a BluetoothDevice in the Discovery callback function? Now it's so easy using it!
When the user clicks an item in our list, we do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { BTListDevItem *item = (BTListDevItem *)[btDevItems objectAtIndex:indexPath.row]; showMessage(@"Connect to:", message); [self deviceConnect <img src='http://www.pocketmagic.net/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> indexPath.row)]; }
And the deviceConnect function, taking a parameter identifying the index of the device we want to connect to , in our array of devices , is even simpler:
/* Bluetooth connectivity */ - (void)deviceConnect:(NSInteger)index { BTListDevItem *item = (BTListDevItem *)[btDevItems objectAtIndex:index]; NSLog(@"deviceConnect to %@", item.name); [item.btdev connect]; }
The connection results
I've tried to connect to a notebook computer equipped with Bluetooth (named Moon-PC) and to a HID Bluetooth Keyboard (named Celluon).
Connecting to the notebook
The notebook exposes the following Bluetooth profiles:
Bluetooth File Transfer Service
Bluetooth Information Synchronization Service
Bluetooth Object Push Service
Bluetooth AV Service
Bluetooth Headset Service
The BluetoothDevice.connect() resulted in the following:
2012-07-16 19:51:25.364 Bluetooth[706:707] deviceConnect to MOON-PC 2012-07-16 19:51:25.366 Bluetooth[706:707] BTM: connecting to device "MOON-PC" C4:46:19:C6:39:D1 2012-07-16 19:51:27.743 Bluetooth[706:707] BTM: attempting to connect to service 0x00000010 on device "MOON-PC" C4:46:19:C6:39:D1 2012-07-16 19:51:27.751 Bluetooth[706:707] BTM: attempting to connect to service 0x00000008 on device "MOON-PC" C4:46:19:C6:39:D1 2012-07-16 19:51:28.994 Bluetooth[706:707] BTM: connection to service 0x00000010 on device "MOON-PC" C4:46:19:C6:39:D1 failed with error 305 2012-07-16 19:51:30.286 Bluetooth[706:707] BTM: connection to service 0x00000008 on device "MOON-PC" C4:46:19:C6:39:D1 failed with error 305
The Celluon keyboard only exposes the HID profile, and here is the connection result:
2012-07-16 19:53:45.727 Bluetooth[706:707] deviceConnect to Celluon 2012-07-16 19:53:45.732 Bluetooth[706:707] BTM: connecting to device "Celluon " 00:18:E4:27:18:39 2012-07-16 19:53:47.204 Bluetooth[706:707] BTM: attempting to connect to service 0x00000020 on device "Celluon " 00:18:E4:27:18:39 2012-07-16 19:53:47.216 Bluetooth[706:707] BTM: connection to service 0x00000020 on device "Celluon " 00:18:E4:27:18:39 failed with error 305
It is clear that the BluetoothManager identified 2 of the 5 profiles exported by the notebook, and the HID profile exported by the Celluon keyboard. These profiles seem to be coded with the hex identifiers shown in the debug content: 0x00000010, 0x00000008, 0x00000020
Even if the connection fails, it is a good starting point in investigating how to establish a solid connection, and receive data. Since the services are recognized by the BluetoothManager , it is surely possible to use the existing functionality, and the already implemented protocols.
This research work has been performed on an iPod, running OS 5.1 .
You can use this code or any parts of it, ONLY if you provide a visible link within your work/project/article, to this webpage. If you agree, you can download the complete source code: Bluetooth iOS Code.
|
|























July 23rd, 2012 at 10:29 pm
Hi, Do you know if we can turn on/off airplane mode or wifi programmatically in IOS 5.1 on a non-jail broken device?
August 1st, 2012 at 1:38 am
Hello! Thank you very much for this great tuorial.
I’ve got an iPhone 4 with iOS 5.1.1 and I’m trying to get a list of bluetooth devices around me. So I’ve compiled your project with xcode, but the App never receives a BluetoothDeviceDiscoveredNotification.
I can’t find why!
I’ve even injected my own discoveryEventCallback (replacing the one in BluetoothManager) to see if the notification was blocked by BluetoothManager but it’s never called (I’m sure of my injection because the same injection with discoveryStatusCallback is working) so the problem would be at the level of MobileBluetooth… strange.
I precise that [btManager deviceScanningEnabled] returns 1 so it isn’t the problem.
Btstack detects my devices.
I have no “apple supported” bluetooth devices to test how they’re discovered so I’m out of solutions…
Did I miss something?
Thanks for any help
August 1st, 2012 at 1:59 am
Wowowooo!!!
Excuse me for this post… Sometimes taking a brake solves the problems!
I solved it like that: replaced [btManager setDeviceScanningEnabled:YES]; with [btManager scanForServices:0xFFFFFFFF];
Thanks again!
August 1st, 2012 at 2:01 am
thanks for your feedback, glad to hear you got it working!
August 3rd, 2012 at 6:28 pm
Hi again!
Do you have an idea of a possible way to access the transfer data when a device is paired?
I have connected a magic mouse, but I don’t really know how to do now.
The events of the apple bluetooth keyboard seem to be implemented in the IOHIDFamily kext but I’m not an expert at reverse engineering so…
Thanks for all the info
August 11th, 2012 at 11:57 am
If someone else is interested, you can access a connected HID device using the IOHIDManager. (an example for MacOSX here: http://www.pjrc.com/tmp/bug.c)
So now I can connect to my two bluetooth mouses and get all the HID reports correctly!
August 21st, 2012 at 9:17 am
That sure looks like an interesting piece of information, did you have the chance to test it?
September 12th, 2012 at 4:23 pm
Hi i m trying to find my iphone with this code i added gamekit framework but nothin happen did you try it to check iphone devices?
September 12th, 2012 at 4:36 pm
actually my purpose is to get something like a id of device the time of checking and the the time of unchecking if i can tell this like dat
September 24th, 2012 at 1:52 pm
Hi,
any idea, why the program is not running on iPad (or iPad Simulator)?
September 24th, 2012 at 3:50 pm
Comiled as iPhone APP and not as Universal App, then the App is running on iPad.
October 19th, 2012 at 3:32 pm
Hi,
I am trying your code and it is function well. many thanks for that.
But one thing is for me not really clear.How did you connect with the service?
thanks a lot.
October 31st, 2012 at 4:42 am
Hi,All;
Like @Guigeek did, I found the bluetooth device; but how could I transfer data between them? Do I need to pair them first?
—-Thank you very much?
November 22nd, 2012 at 8:00 am
Hi KD,
If you want to run this app on iPad Simulator then you have to replace following method in BTAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[BTViewController alloc] initWithNibName:@”BTViewController_iPhone” bundle:nil];
//} else {
// self.viewController = [[BTViewController alloc] initWithNibName:@”BTViewController_iPad” bundle:nil];
// }
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Thanks,
Cp
December 19th, 2012 at 1:53 am
Its really great work.If I want to know if paired device is bluetooth audio device , can I know that?
Thanks,
Snehal
December 31st, 2012 at 7:33 pm
[...] tried to do an app for fun that can turn off and turn on bluetooth. I followed this and this but when i try to run my project i found an error : Lexical or Preprocessor issue [...]
January 15th, 2013 at 5:34 pm
[...] I used the following examples to make use of the iOS BluetoothManager private API: http://www.pocketmagic.net/2012/07/bluetooth-and-ios-use-bluetooth-in-your-iphone-apps/#.UPPx_eSIWc8 [...]
February 10th, 2013 at 4:43 pm
[...] is it. Simply I am following this tutorial, but added the steps here just in case the tutorial went [...]
March 2nd, 2013 at 6:23 pm
Hi, thanks for your tutorial and sample, it’s running well until I got the “failed with error 305″ log.
In my application I want to connect accessory without doing setting in “setting->bluetooth”.
Here I have 2 questions:
1)How to connect to the Accessory correctly?
2)Normally after I click “scan” information of the accessory show up in the tableview shortly, but if I click the item trying to connect it, I got the “failed with error 305″, after that the accessory can never be detected again when scanning, no matter how many times I restart the application and accessory. Only after I restart the iPhone, the accessory can be detected again. Why? and How to do with it?
March 4th, 2013 at 2:24 pm
[...] Bluetooth and iOS – Use Bluetooth in your iPhone apps [...]
March 7th, 2013 at 2:03 pm
[...] sample code [...]
March 19th, 2013 at 6:53 pm
Hi,
I was able to scan for devices and to pair the device, too.
But then I was not able to connect and transfer data… Can you give me directions?
March 22nd, 2013 at 2:32 pm
Hi Guys,
I am new to the development of apps on iOS, in my app I want to get the already connected blue-tooth device name to iOS device. I need the blue-tooth device name to have some user interface. As I am new to this can some one suggest regarding getting the already connected device name without scanning for the blue-tooth devices.
Waiting for your reply.
Thanking you in advance.
Sam
April 5th, 2013 at 9:22 am
Hi,
I have used your framework, but I have one issue, when the device get disconnected with other is there any notification called so that I should know that the XYZ device is disconnected. Like you have given the “BluetoothDeviceDiscoveredNotification” same as that.
Basically I am creating an app that should give me notification like discovered device is disconnected.
Waiting for your reply. Thanks in advance.
Pradip
April 8th, 2013 at 7:26 am
Hi, I want to use this app to connect to a Bluetooth Low Energy device. The app works on my iPad after making the changes above and finds standard bluetooth devices but cannot find my BLE device. However, I found a paid app that finds the device and connects to it. Is there something I have to add or change to get this app to connect to BLE devices?
Thanks
Kyle
April 10th, 2013 at 4:30 pm
Hi, Radu,
Thanks for the good work and sharing. I was wondering, is there an environment variable you set so that you can get the debug information like the following?
BTM: connecting to device “MOON-PC” C4:46:19:C6:39:D1
Perhaps an environment variable for BluetoothManager?
Thanks, –Major
April 12th, 2013 at 10:39 am
@Guigeek: I am not able to see [btManager scanForServices:0xFFFFFFFF]; Can you please help me? I want to pair Bluetooth headset within the app.
April 19th, 2013 at 11:00 pm
Hello Radu, thanks this website is very helpful. Now I am tying to pair/connect to a device where I know the BT address. I don’t want to run the scan. So I believe I need to create a BluetoothDevice object like this: BluetoothDevice* btDev = [[BluetoothDevice alloc] initWithDevice:xxx];
The parameter xxx is of type (struct BTDeviceImpl *). Do you know how this struct is defined? I couldn’t find anything about it.