I'm able to enable Bluetooth with help of the Private Framework.
Now I have to search for nearby devices.
I guess the deviceScanningEnabled command is the right one, but how do I get the returned Devices? Is there any callback-Function? I read about some Notifications which will be in the NotificationCenter?!
How do I use it in this context?
As far as I know, the bluetooth manager gets the list after OS has filtered the results - meaning you will only get the nearby headset devices and not all generic devices. If you need to find all generic devices you will have to use #rajagp's answer.
In the case that finding headsets are enough, then you can use notifications as you said; the notification for discovering a device is called "BluetoothDeviceDiscoveredNotification". You first need to list the notifications with:
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: #selector( your_discovery_method_name)
name: #"BluetoothDeviceDiscoveredNotification"
object: nil];
the "your_discovery_method_name" is the method you write that shows/accepts the notification. It will look something like this:
-(void) your_discovery_method_name:(NSNotification *) notification {
self.device = [notification object];
NSLog(#"found: %#",self.device.address);
// ...
}
The device is from type BluetoothDevice.
If you are developing for a jailbroken phone , I'd recommend the third party BlueTooth library - BTStack. Its easy to use and has been working quite well for me. Its available at : http://code.google.com/p/btstack/.
replace
[btManager setDeviceScanningEnabled:YES];
with
[btManager scanForServices:0xFFFFFFFF];
i don't know why, but you'll discover all the devices nearby. Then you can pair the device.
This is where i got stuck... i am not able to get connections or exchange data
Related
I am writing an iOS-based program that interacts with a Bluetooth device via the External Accessory Framework. I would like to determine ahead of time if Bluetooth is even enabled before attempting to connect. Unfortunately, I don't see anything in the External Accessory Framework documentation that allows me to do this.
After checking the docs for the [EAAccessoryManager][1], the closest I can find is to check the [connectedAccessories][1] list to see if any devices are currently connected. However, this doesn't directly indicate the Bluetooth adapter's status.
There are plenty of examples on SO pertaining to Core Bluetooth and Bluetooth LE. I'm specifically looking for a solution related to the External Accessory Framework.
This is not possible with the ExternalAccessory framework. You should use CoreBluetooth, which can give you the information you need on devices that have BLE hardware, i.e. everything released after 2011. The fact that you are using ExternalAccessory for communication with your device does not prevent you from also using CoreBluetooth just for the purpose of knowing whether Bluetooth is turned on.
For older devices there is no way to get this info with public APIs, however if you are not intending to publish your app on the App Store you can use the private BluetoothManager framework.
To get the info with CoreBluetooth you will need to instanciate a CBCentralManager instance, for example like this :
centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
and then implement the following delegate method to get the relevant info :
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
BOOL bleAvailable = central.state != CBCentralManagerStateUnsupported;
if (bleAvailable) {
BOOL bluetoothTurnedOn = central.state != CBCentralManagerStatePoweredOff;
// Do something with the info
}
else {
// Out of luck... We won't be able to determine whether BT is on or off
}
}
I'm trying to learn about CoreBluetooth and External Accessories on iOS.
First, I tried to see a list of devices connect to my phone via Bluetooth via print(EAAccessoryManager.sharedAccessoryManager().connectedAccessories) ... despite having 3 devices connected (according to the Settings app), I'm given an empty array.
Next, I tried registering for connect / disconnect notifications:
import UIKit
import ExternalAccessory
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "somethingConnected:",
name: EAAccessoryDidConnectNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "somethingDisconnected:",
name: EAAccessoryDidDisconnectNotification,
object: nil)
EAAccessoryManager.sharedAccessoryManager().registerForLocalNotifications()
}
func somethingConnected(name: EAAccessory) {
print("here")
}
func somethingDisconnected(name: EAAccessory) {
print("there")
}
}
... I receive nothing when I turn off/on (and thus disconnect/connect) a simple Bluetooth speaker I have.
I am seeing this issue (notifications not delivering until after the completion block of showBluetoothAccessoryPickerWithNameFilter() executes), but, generally, it seems like either:
A) Something with iOS isn't working correctly
B) I'm doing something wrong (the more likely of the two).
Do I need to have a special MFI certificate installed to see a list of connected Accessories? Why aren't notifications delivering?
Any recommendations / code examples are greatly appreciated.
Update
Most importantly: Still don't know why connectedAccessories doesn't work, so advice on this piece is greatly desired.
That said, re-reading the Apple Developer documentation, I don't believe that it's correct / possible to use NSNotificationCenter.defaultCenter().addObserver with these types of notifications.
Specifically, the documentation states that EA notifications will not be delivered until showBluetoothAccessoryPickerWithNameFilter() is called -- e.g. the EAAccessoryDidConnectNotification and EAAccessoryDidDisconnectNotification are meant to inform the app about what the User did with the picker dialogue. It doesn't seem that they are system-level notifications that can be picked up by NSNotificationCenter.
Please correct me if this is an incorrect reading.
you should change
selector: "somethingConnected:"
into
selector: #selector(somethingConnected:)
,than it will fire.
For more details, please see the following website:
Why does EAAccessoryDidConnectNotification occur twice?
For an application I'm working on we are trying to log whether an iDevice is using an external GPS accessory such as the xgps. I've become a little confused exactly how to do this.
I understand there is a (NSArray *)retrieveConnectedPeripheralsWithServices:(NSArray *)serviceUUIDs call which might help but I'm unsure what to use for the serviceUUIDs and I couldn't really find much from the documentation. I understand I'm looking for A list of service UUIDs (represented by CBUUID objects).
Is there some sort of standardized list in the bluetooth Spec I should be using? I didn't see anything listing GPS here: http://bluetooth-pentest.narod.ru/doc/assigned_numbers_-_service_discovery.html
So in Summary:
In iOS 7 is there an easy way to query for connected bluetotooth devices and get information on them and if so could somebody provide a code sample?
Thanks
/* Store all the Bluetooth accessories currently connected */
NSArray *accessoryList = [[EAAccessoryManager sharedAccessoryManager] connectedAccessories];
for (EAAccessory *acc in accessoryList) {
// here you can do all your stuff by accessing acc
acc.firmwareRevision;
acc.hardwareRevision;
acc.manufacturer;
acc.modelNumber;
acc.serialNumber;
acc.name;
//etc
}
Larme pointed me to the link here: Display Bluetooth devices (Not BLE devices) in a UITableView
which specifies a call to:
NSArray* accessoryList = [[EAAccessoryManager sharedAccessoryManager] connectedAccessories];
which does the trick!
This is a short question but it was bugging me for a whole night. I have few of my own applications here (I write Objective-C Only and I use ARC) where if I write in appDelegate - application didFinishLaunching...:
[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(proximityStateChanged:) name:UIDeviceProximityStateDidChangeNotification object:nil];
I get perfectly normal response. Display turns off, I get notification with changed proximityState, etc.
Now, I have application that is not mine and I should modify it (I have Xcode project - source files). I only should implement some changes based on proximitySensor. I am absolutely unable to enable proximityMonitoring? I am doing the same thing as in other applications but it is simply not calling the notification and not changing proximityState. Biggest difference is that this application's appDelegate is .mm - mixed language, but I really don't think this should be a problem.
Is there some GLOBAL way to disable sensors or only proximity sensor? Can some service for recording audio or playing audio be able to disable proximity sensor? Any clue would be golden! I really don't understand what could be preventing me from enabling this feature.
Cheers everyone.
FUU!
ProximitySensor is being disabled if the application doesn't support Portrait orientation! You can do whatever you want, but if Portrait is not checked as a Device Orientation, ProximitySensor wont start up!
It's not clear what you're asking. When you say you "have an application that is not mine", do yo have the source code, or are you looking to patch it somehow?
If you have the full source code you should be able to insert the same calls you show above and have them work. You would need to turn on proximity monitoring, add an observer, and then add your observer method to the class that you've added as an observer.
I don't think you have to set a flag in the info.plist file in order to enable proximity monitoring, but I'm not positive. I've only ever used it as an experiment, and that was a while ago.
I know you can use this service to have devices like smart watches intercept notifications from iOS devices. But can you receive these iOS notifications on a Mac through OS X?
I want to be able to have my OS X program detect a specific notification type that is received in iOS. I tried browsing for the ANCS device on my Mac, but it didn't show up. I know you can't do this between iOS devices, so I was wondering if maybe the same was true between iOS and OS X or not?
Thanks!
It's definitely possible!
Here's what you need:
An app on your iOS device which imports CoreBluetooth and uses CBPeripheralManager to advertise a dummy service with some custom UUID (not the ANCS UUID, it won't work). This dummy service is required for your Mac to "see" the ANCS service.*
An app on your Mac which imports IOBluetooth, initiates a CBCentralManager object, and starts a scan. You can do this as so:
[self.centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:YOUR_CUSTOM_SERVICE_UUID]] options:#{CBCentralManagerScanOptionSolicitedServiceUUIDsKey:#[[CBUUID UUIDWithString:ANCS_SERVICE_UUID]]];
Make sure you set yourself up as a delegate to CBCentralManager to receive the delegate callbacks.
When your Mac discovers your device in didDiscoverPeripheral, connect to it:
[self.centralManager connectPeripheral:peripheral options:nil];
1 very important thing to note here is you need to retain your peripheral to a property if you wish to connect to it, otherwise it will be dealloc'ed. See this answer for a more detailed discussion.
In didConnectPeripheral, you need to set yourself up as a delegate to the CBPeripheral you're connected to then start discovering services:
[peripheral discoverServices:nil];
(All the callbacks from this point onward are for CBPeripheral)
In didDiscoverServices, you should get a list of available services. Loop through them as so and discover each service's characteristics:
for (CBService *service in peripheral.services) {
if ([service.UUID isEqual:[CBUUID UUIDWithString:YOUR_CUSTOM_SERVICE_UUID]]) {
NSLog(#"Found your Custom Service");
}
if ([service.UUID isEqual:[CBUUID UUIDWithString:ANCS_UUID]]) {
NSLog(#"Found ANCS Service");
}
[peripheral discoverCharacteristics:nil forService:service];
}
In didDiscoverCharacteristicsForService, you want to look for 3 characteristics:
ANCS Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
ANCS Control Point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
ANCS Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)
For those notifiable characteristics, subscribe to them for updates:
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:ANCS_CHARACTERISTIC_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
If you want to check if those characteristics are have started notifying, do a if(characteristic.isNotifying) in didUpdateNotificationStateForCharacteristic.
You will get the actual NSData updates in didUpdateValueForCharacteristic with characteristic.value. The important thing to note here is that you will get informed of notification events by the Notification Source characteristic, but these will not contain that much information. If you want your Mac to play a sound or flash some Hue lights or something like that for every iOS notification, this will suffice. However, for the actual notification details, it will need to come from the Data Source characteristic, but you need to request for them by making very specific calls to the Control Point characteristic. This is where it gets really complicated, and you'll be able to get more information in the official ANCS Specification document.
If you want a shortcut or a look at how others have done it, check out these Github repos:
jamiepinkham/BTLE_ANCS
KhaosT/ANCS-Mac
indragiek/INDANCSClient
Just be careful as you may find bugs in some of these implementations, mainly in the processing of data sent by the ANCS Data Source (I had to get creative with my own error handling).
*** Some may argue that you can use "Service Solicitation" to expose ANCS without having an app running on the iOS device and/or without advertising a dummy Service (see options parameter in Step 2), but I haven't had that much success with it so perhaps there's something I'm missing.