I want to exchange some data between two android devices using Bluetooth LE (and yes, I know that I'm not intendet exchanging data with BLE, but thats not the point here).
So I started researching on that topic and found out that the device used as peripheral needs android 5, while the core device will need android 4.3.
The first step would be starting a BluetoothGattServer on the peripheral, then advertise it and finally start scanning for it with the core device.
I understand that advertising was added in android 5 but BluetoothGattServer exists since android 4.3.
So if I would just create the BluetoothDevice object to which the core should connect from a address string (which I got), there is no need for advertising the peripheral.
If advertising isn't necessary I could just stick to android 4.3 without the need of a 5.0 device.
But somehow I got a strange feeling about this, like I'm getting something wrong? Any suggestions?
Advertising is necessary for peripheral since if it was no advertising, the central can not find the device(OK I assume you have the peripheral MAC address) but if central could not receive the advertising will not send out the connect request, hence the connection would not be set up.
I understand that advertising was added in android 5 but
BluetoothGattServer exists since android 4.3
I assume you mean that 4.3 can support BLE and advertising/BluetoothGattServer exists on android 5 right?
If you just transfer few bytes, why don't you use SPP or OPP.
Related
I am currently working on a project that involves building a BLE peripheral and client. I read about the UUIDs in this document https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf and assigned my own UUIDs to them of the document that fit the description, e. g. turning a light on and off to 0x2B01 Luminous Intensity. However, that resulted in different behavior depending on the phone and android version used for the client. My phone, Android 11 / Xiaomi Mi A3, did work well with the set characteristics and their assigned UUIDs. My friend's phone, an Android 12 / Samsung S20, did not discover the characteristic. Moreover, when trying other UUIDs of the document, his phone could not read the characteristic, but mine did. That brings me to my questions:
Are these UUIDs predefined on some devices?
Can I safely assign my own UUIDs without getting in trouble of one phone not caring at all what the UUID says about the characteristic but another does?
It was a classic Gatt cache problem. My phone clears the Gatt cache somehow periodically, or every time it connects to a BLE device, while the Samsung phone does not. The solution was to clear the cache when discovering available services.
I am searching for some way that can connect to Bluetooth devices without pairing. Or at least make a connection first and then it does not need to be established all the time. Like how wearable devices work (i.e. mi band 6 or Huawei band 6). Can someone please guide me towards some helpful demo or documentation for this somewhere?
Also, I was wondering how was the security managed since my Bluetooth is always on to communicate to the wearable device. Though, turning off discoverability does not seem to create any issues in order to communicate with the device.
Most wearables nowadays use Bluetooth Low Energy (BLE), and with BLE you don't need to pair in order to exchange data - i.e. only a connection is needed. That being said, it is recommended to pair as the data exchanged between the wearable device and the phone will be encrypted, in addition to some other benefits in terms of privacy and security, Have a look at the links below that will go over connection/pairing in more detail:-
Should one create a bond with BLE device
The Ultimate Guide to Android Bluetooth Low Energy
Making Android BLE work
https://developer.android.com/guide/topics/connectivity/bluetooth-le#roles
Central vs. peripheral. This applies to the BLE connection itself. The
device in the central role scans, looking for advertisement, and the
device in the peripheral role makes the advertisement.
To check if a device supports "peripheral"/advertisement mode it looks as though I can use getBluetoothLeAdvertiser()
getBluetoothLeAdvertiser
added in API level 21 public
BluetoothLeAdvertiser getBluetoothLeAdvertiser () Returns a
BluetoothLeAdvertiser object for Bluetooth LE Advertising operations.
Will return null if Bluetooth is turned off or if Bluetooth LE
Advertising is not supported on this device.
Use isMultipleAdvertisementSupported() to check whether LE Advertising
is supported on this device before calling this method.
Now I've heard some rumors that some devices can actually give you a BluetoothLeAdvertiser, but return false on isMultipleAdvertisementSupported() which is another issue in itself, but on the central side of things, the docs don't say anything!
Am I missing something? https://developer.android.com/reference/android/bluetooth/BluetoothAdapter doesn't say anything about central mode. Am I missing something basic here? Thanks for any help. I have heard bluetooth is a pain on Android and it is my first day exploring these APIs.
Short Answer
As DigitalNinja pointed out, an Android phone will always support Central role functionality by default, so if your phone supports BLE, then it can definitely operate in the central Role
Long Answer
You're right, the API might not be straight-forward but this is down to how Bluetooth Low Energy (BLE) API was added to Android and even down to the history of BLE technology itself.
When BLE was first introduced, it was aimed to be for sensors only (e.g. thermometer, heart rate, proximity, etc) and devices that talk to these sensors. The sensors were the peripherals in this case, and the devices that talk to these sensors are the centrals. The peripherals were the true Low Energy (LE) devices, as they would just advertise and send data once in a while. Centrals on the other hand would not be very power efficient as they would have to continuously scan for devices, connect to these devices, and remain in charge of maintaining and monitoring that connection, meaning the radio would be on for a much longer time when compared to the peripheral.
When Bluetooth Low Energy (BLE) API was added to Android, it supported Central role only. In other words, you could write an Android app to scan and connect to peripherals (sensors), but the Android device itself could not act as a peripheral (Because the assumption was that you wouldn't need an Android device to act as a sensor). This was done in Android 4.3 (API 18).
As people started to use BLE more often and the technology matured, it started being used for all sorts of different applications (e.g. virtual serial port, data transfer, beacons, etc). Moreover, standalone central devices started appearing in the market and there was a need to use them with phones or at least test them out against phones/tablets during the development stages. As such, the distinction between central and peripheral started becoming fuzzier and fuzzier, and there was a demand for Android to start supporting peripheral role. This is when the BLE API was updated to introduce peripheral role functionality, which happened in Android 5.0 (API 21).
So to answer your question, if BLE is supported on an Android device then it is safe to state that it will by default support central role as this is the foundation of the BLE functionality for Android. However, API was introduced later to support the peripheral role, which is why not all Android devices that support BLE will support peripheral role.
Finally, please note that isMultipleAdvertisementSupported is a different feature which indicates if your device supports sending out multiple adverts at the same time. Some devices support sending out different adverts simultaneously, while others don't. However, this does not mean that they do not support advertising at all. A device that supports isMultipleAdvertisementSupported will definitely support BluetoothLeAdvertiser, but the other way around is not guaranteed.
To conclude, the safest way to check if your device supports central and/or peripheral role is through the Android version and the API level used, as indicated by the two links above. On Android 5 (API 21) onwards, you can write applications that support both central and peripheral roles, whereas before that you can only write applications for the central role.
I hope this helps.
I've built a dual mode Bluetooth device using the BT 121 from Silicon Labs. The device implements SPP over the classic connection. The device name of the classic node is "XYZ Classic". It also implements a custom service (128-bit UUID) in BLE. The device name of the BLE node is "XYZ_BLE". Both nodes have the same MAC address.
When pairing under 'Bluetooth' settings, sometimes I will see 'XYZ Classic' and sometimes I will see 'XYZ_BLE'. It seems random which one it will pair to but many Android devices I've tested have a tendency to want to pair to the classic node. After pairing, a connection over classic/SPP ALWAYS works. However, I can only connect to the custom service if paired to the BLE node. If paired to classic I can see non-custom BLE services but not my custom service. To summarize:
Function Classic Pairing BLE Pairing
Spp Works Works
Cust BLE Doesn't Work Works
When I pair in code (Android) the problem also happens despite the fact that I search for the devices named 'XYZ_BLE' and then pair to the device returned. I've looked but I can't see a way to force Android to pair to the BLE node.
My only workaround thus far has been to modify my BT 121 firmware to not allow bonding in classic mode. This is not an ideal solution has any Bluetooth Classic only devices will not be able to bond with my device (In reality this might not be too big of a problem but I have one tablet in my possession that only has Bluetooth Classic).
It should be noted that I've used 'BLE Scanner' from the play store to verify that my custom service works/doesn't work depending on the pairing mode. In other words, it's not just my code. :)
So, does anybody have any ideas on how to force Android to pair to the BLE node?
I see similar issues. Some hints:
Android behaviour differs dependent on the bit flags you set in the BLE advertising. There is for example a bit called "no br/edr support" or so. There are also bits telling explicitly that br/edr dual role is supported.
Also ble pairing may be enforced if you access a characteristic which returns a "not authenticated error" from a ble app. At least on iohone, the os will initiate the ble pairing automatically.
I'm trying to make an application which uses the new Bluetooth Low Energy API of Android. For this, I started with the BLE sample coming with API level 18.
As I read that Android can not act as a Peripheral, I put the Android phone in central mode, scanning for BLE devices around it. For this purpose, I made some testing with a Nordic Platform simulating a Heart Sensor. Everything works in a perfect way!
After this, I try to pick an iPhone (iOS 7 beta 4) and put it in a Peripheral way and simulating a Heart Rate sensor as the previous testing. The Android app is able to see the device and connect to it. But after the connection is active, the 2 devices disconnect from each other in 3-4 seconds. In addition to that, when I call discoverServices() on Android side, no callback is triggered! In some cases the Android device receives the "Connected" event even if iOS Bluetooth chip is Off. This is very strange. To prove that, I put the Nordic Board in Central mode and I was correctly able to connect to the iOS device with no problems.
What could it be? There are some limitations on Android or iOS that don't permit to connect from an Android to an iOS or viceversa?
Thanks.
EDIT: After some hard testing, I raised an issue on the AOSP page. It can be checked here
Adding a summary for reference:
What could it be? There are some limitations on Android or iOS that don't permit to connect from an Android to an iOS or viceversa?
When connecting to a GATT server that is advertised as dualmode (BLE and BR/EDR) device by calling connectGatt(...), the TRANSPORT_AUTO flag that is internally added makes Android to default to the BR/EDR mode (link).
Following workarounds are possible:
Peripheral side: Stop advertising BR/EDR capabilities by adjusting
the appropriate flags (link)
Central side: Set the transport parameter explicitely to
TRANSPORT_LE by calling the hidden version of connectGatt() using
reflection
Example:
public void connectToGatt(BluetoothDevice device) {
...
Method m = device.getClass().getDeclaredMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
int transport = device.getClass().getDeclaredField("TRANSPORT_LE").getInt(null); // LE = 2, BREDR = 1, AUTO = 0
BluetoothGatt mGatt = (BluetoothGatt) m.invoke(device, this, false, gattCallback, transport);
...
}
Edit 4/2016
As Arbel Israeli pointed out in the comment, Google introduced an overloaded version of connectGatt(...) which allows to specify the transport in Android M.
I've written a simple working example, well relatively simple, and included it open-source on Github: https://github.com/GitGarage. So far it has only been tested with an Android Nexus 9 and an iPhone 5s, but I presume it would also work with a Nexus 6 and various iPhone types. So far it is set up explicitly to communicate between one Android and one iPhone, but I presume it is tweakable to do much more.
Maybe a bit delayed, but perhaps your pain can be relieved slightly ;)
We have been experimenting a lot with cross platform BLE connections (iOS<-> Android) and learned that there are still many incompatibilities and connection issues. Aside to the instability of Android you should also consider that still, as of today, not that many Android devices actually support the BLE Peripheral mode.
Therefore, if your use case is feature driven and you only need basic data exchange I would suggest to look at Frameworks and Libraries that can achieve cross platform communication for you, without you needing to build it up from scratch.
For example: http://p2pkit.io or google nearby
Disclaimer: I work for Uepaa, developing p2pkit.io for Android and iOS.
You can now pass in TRANSPORT_LE via BluetoothDevice.connectGatt as of API 23.
Please see Android Documentation references below:
TRANSPORT_LE
Bluetooth.connectGatt
iOS Devices always be a peripheral or central but Android devices cant be rarely.In this case your iOS device must be a peripheral and android must be a central.We can think peripheral is a server and central is a client.This is simple.