How to connect Android device to an iOS device over BLE (Bluetooth Low Energy)

AndroidIosBluetooth LowenergyCore BluetoothAndroid 4.3-Jelly-Bean

Android Problem Overview


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

Android Solutions


Solution 1 - Android

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:

  1. Peripheral side: Stop advertising BR/EDR capabilities by adjusting the appropriate flags (link)

  2. 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.

Solution 2 - Android

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.

Solution 3 - Android

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.

Solution 4 - Android

You can now pass in TRANSPORT_LE via BluetoothDevice.connectGatt as of API 23.

Please see Android Documentation references below:

Solution 5 - Android

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionedoardotognoniView Question on Stackoverflow
Solution 1 - AndroidDominik GebhartView Answer on Stackoverflow
Solution 2 - AndroidomikesView Answer on Stackoverflow
Solution 3 - Androidp2pkitView Answer on Stackoverflow
Solution 4 - AndroidKevin CrainView Answer on Stackoverflow
Solution 5 - AndroidMustafa DemirView Answer on Stackoverflow