I am working with the Core Bluetooth API in iOS 8.4. My code is interacting with a BLE device that is programmed to be an iBeacon. Here is a logging statement produced by my implementation of the CBCentralManager protocol's didDiscoverPeripheral callback function:
2015-09-04 16:23:08.231 CentralManager - Did discover peripheral [CBPeripheral: 0x1742e0b80, identifier = 8B63C7F8-44D5-F3E2-AD40-2916A2513BA9, name = DfuTarg, state = disconnected] with data [[kCBAdvDataIsConnectable: 0]]
The logging statement prints the value of the function's peripheral and advertisementData arguments. Note that the name of the peripheral is printed (BTW: I happen to know that DfuTarg is the correct name of the device being scanned).
From where does iOS acquire this name? It is not part of the Advertising Packet. It must come from a secondary Scan Request / Scan Response exchange, yes? Is it possible for my code to access the Scan Response?
Yes, the CBPeripheral name comes from the scan response. CoreBluetooth automatically requests the scan response data (at least when the app is in the foreground) when an advertisement is detected.
The didDiscoverPeripheral method is called with information from both the initial advertisement and the scan response when both have been received by the device. Essentially, you are already accessing the scan response info by using that callback method.
What's important to note is that you do not have access to raw manufacturer data in this callback when the advertisement is recognized as an iBeacon. iOS strips it out so you can't access it. This is true for the manufacturer data bytes present in the advertisement and in the scan response.
See here for more info.
Related
So I am developing an application which interacts with a bluetooth peripheral, and I am running into the issue that there is currently no way to tell if the user rejected the peripheral's pairing request or not.
The current flow which is implemented is:
Scan for peripherals
Connect to peripheral
Discover services
Discover characteristics
(Pairing request is sent here by the peripheral, and the OS presents the pairing permission popup)
Read from characteristics
I would like to present an error state if the user rejects the pairing request, but I do not seem to be able to tell whether this has happened:
There is no error callback executed on the CBCentralManagerDelegate or CBPeripheralDeleagate
All the characteristics are discovered, whether or not paring has been accepted
Reading from/ writing to characteristics fails silently: i.e. the peripheral just doesn't return a value when a characteristic is read from, but there's no affirmative error to let me know that it's because of a permission failure.
According to this article it indicates that there's no direct way to know that the pairing request was cancelled.
According to this answer it looks as if there is not currently a direct way to detect whether a peripheral is bonded in iOS.
Is there any known workaround for this issue?
I am trying to connect BLE device using his hex number written on his peripheral name. but the peripheral name is different for some reason on different devices.
What could be the reason for that?
also i tried to find it inside advertisementData but without success.
thanks
Your device might have the shortened name in the advertisement data but have the longer one in the scan response.
If you're scanning while the app is in the foreground, you'll get the full scan response data, so it might not matter in your app. You just might have to ignore the first callback that doesn't have scan response data.
Explanation :
I am connecting to BTLE peripheral using core bluetooth framework, saving the peripheral identifier in a database.At the same time, I am saving the peripherals in an array to handle reconnection with peripherals.But, when user manually quit the app, my array becomes empty. due to which I won't be able to reconnect those peripherals again.
Now, I have peripherals identifiers in my database. I have read about it and found that there is a delegate method
- (NSArray<CBPeripheral *> *)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID *> *)identifiers NS_AVAILABLE(NA, 7_0)
To get the peripherals but it returns nothing.How I can get the peripherals again?
https://developer.apple.com/library/content/documentation//NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithA
I also check above document. In that they mentioned about the methods to reconnect to the peripherals
Retrieving a List of Known Peripherals
The first time you discover a peripheral, the system generates an identifier (a UUID, represented by an NSUUID object) to identify the peripheral. You can then store this identifier (using, for instance, the resources of the NSUserDefaults class), and later use it to try to reconnect to the peripheral using the retrievePeripheralsWithIdentifiers: method of the CBCentralManager class. The following describes one way to use this method to reconnect to a peripheral you’ve previously connected to.
When your app launches, call the retrievePeripheralsWithIdentifiers: method, passing in an array containing the identifiers of the peripherals you’ve previously discovered and connected to (and whose identifiers you have saved), like this:
knownPeripherals =
[myCentralManager retrievePeripheralsWithIdentifiers:savedIdentifiers];
The central manager tries to match the identifiers you provided to the identifiers of previously discovered peripherals and returns the results as an array of CBPeripheral objects. If no matches are found, the array is empty and you should try one of the other two reconnection options. If the array is not empty, let the user select (in the UI) which peripheral to try to reconnect to.
When the user selects a peripheral, try to connect to it by calling the connectPeripheral:options: method of the CBCentralManager class. If the peripheral device is still available to be connected to, the central manager calls the centralManager:didConnectPeripheral: method of its delegate object and the peripheral device is successfully reconnected.
Note: A peripheral device may not be available to be connected to for a few reasons. For instance, the device may not be in the vicinity of the central. In addition, some Bluetooth low energy devices use a random device address that changes periodically. Therefore, even if the device is nearby, the address of the device may have changed since the last time it was discovered by the system, in which case the CBPeripheral object you are trying to connect to doesn’t correspond to the actual peripheral device. If you cannot reconnect to the peripheral because its address has changed, you must rediscover it using the scanForPeripheralsWithServices:options: method.
On application startup I would just discover all the peripherals and then compare discovered peripherals with the peripheral identifiers stored in the database.
After the comparison of the discovered peripherals and peripherals, the connections for desired peripherals can be made.
I'd like to ask whether it is possible to access the raw advertisement data from a custom BLE device built using a Raspberry Pi from the Core Bluetooth API?
The use case is to broadcast constantly changed data from the Raspberry Pi to multiple iOS devices in the proximity and consume them in an iOS app. See the topology description in this article.
I already found out that the iBeacon advertisements are filtered out from the Core Bluetooth API and are only accessible from the Core Location API only, which requires the knowledge of the UUID. Due to the constantly changed data a custom iBeacon wouldn't work for this particular use case anyway. But I am unsure whether I could achieve that with Core Bluetooth?
You can do what you want if you change the Raspberry Pi to transmit a non-iBeacon format. CoreBluetooth only filters out the raw bytes of advertisements if they are iBeacon advertisements. See here: Obtaining Bluetooth LE scan response data with iOS
A simple solution is to change your iBeacon advertisement to an open-source AltBeacon advertisement. CoreLocation will no longer pick it up, but CoreBluetooth will.
Here's an example of what you get in the advertisementData NSDictionary in the CoreBluetooth centralManager:didDiscoverPeripheral:advertisementData:RSSI: callback. This example is the result of detecting an AltBeacon advertisement (an open-source beacon standard), with identifiers 2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6 1 2:
{
kCBAdvDataIsConnectable = 0;
kCBAdvDataManufacturerData = <1801beac 2f234454 cf6d4a0f adf2f491 1ba9ffa6 00010002 be00>;
}
You can see how to decode the above bytes by looking at the AltBeacon spec here. Note that the above are the actual contents of the NSDictionary for a detected advertisement on iOS8 that were printed to the console using an NSLog statement.
Quick answer is "there is no direct way".
Why:
Because CoreBluetooth filters out advertisement data, except kCBAdvDataServiceUUIDs, kCBAdvDataLocalName, so there is now way to pass custom data from peripheral to central via advertising.
How can we workaround:
Peripheral
1) Holds some custom service (let's name it 'BeaconService').
2) BeaconService contains Beacon's UUID, major, minor characteristics.
3) Advertises BeaconService UUID (via kCBAdvDataServiceUUIDs key).
Central
1) Scans for peripherals that have BeaconService UUID.
2) Found peripherals are queued.
3) Connection is opened to queued peripherals, and the iBeacon information is read from BeaconService.
4) Read values can be used to start CoreLocation beacon monitoring/ranging.
So by this way you can make bridge from CoreBluetooth to CoreLocation.
I'm trying to learn more about by this sample provided by Apple.
This sample can send text from an iOS device to another one.
There is a method called:
-(BOOL)updateValue:(NSData *)value forCharacteristic:(CBMutableCharacteristic *)characteristic onSubscribedCentrals:(NSArray *)centrals;
When this sample send text by this method, it will return a BOOL to let you know succes or not.
It's easy and clear.
But I have doubt about :
Is this provide by BLE?
Or it's because of CoreBluetooth API?
In other words , If I receive data from other BLE device(not iOS device).
Could that device know that I've received data?
In BLE, when your central device (here iOS device, assumed to be master, and also the client) wants to send data to a peripheral device (assumed to be slave and the server), it has several options to do it:
(1) write to a characteristic value
(2) write command to a characteristic value
The difference is (1) has a response from the peripheral device. (2) doesn't have that. The advantage of (2) over (1) is that (2) can send multiple data blindly while (1) has to wait until there is a response to previous write before it could send next data.
Similarly, if your peripheral device (as server) wants to send some data to your iOS device, you could either indicate (with acknowledgement) or notify (without ack).
Hope this helps.