82

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

Pedro Lobito
  • 75,541
  • 25
  • 200
  • 222
edoardotognoni
  • 2,702
  • 3
  • 18
  • 31
  • 2
    According to the documentation, Android DOES support running as a server (for example a Heart Rate monitor) though the values one generates will be fake. On the other hand, there are no examples, the documentation tells you to do wrong things, and there is no way to start advertisements (though the documentation says you can). – Brian Reinhold Aug 08 '13 at 13:51
  • You're right. I've already found the doc bug about BluetoothGattServer. You can not have the GattServer instance with getProfileProxy method (as doc says), but you can from the BluetoothManager.openGattServer(). It's already been reported to google as an issue. Anyway, yes Android can act as a GattServer but it can not advertise. If you might be interested, I've already tested and after the conenction of the 2 devices, the remote can see the Gatt servers exposed from Android. Check first answer's comments to see my issue report about this question. – edoardotognoni Aug 08 '13 at 14:01
  • Yea, I stumbled on that too and added my two cents to that issue. Now I have a Thermometer server that can't advertise so I can't use it. – Brian Reinhold Aug 09 '13 at 12:57
  • I opened a thread nearly identical to yours: http://stackoverflow.com/questions/18410081/communicating-between-ios-and-android-with-bluetooth-le I will watch this thread for any solutions you find. – afrederick Aug 23 '13 at 19:55
  • Read the Android issue I posted in the EDIT section of the question. It's clearly explain why this process is failing. it's an Android fault we think. Mainly is sending a not permitted message over a fixed BLE channel. I think the only thing we can do is to wait for a new Android release :( – edoardotognoni Aug 25 '13 at 01:11
  • @edoardotognoni Yeah I saw that, pretty big bummer, hopefully it's a priority for the next revision – afrederick Aug 25 '13 at 20:17
  • Bluetooth LE does not maintain connections the way Bluetooth Classic does. Monitoring an attribute is done with notifications. Android should sign up for notifications when iOS Charateristic change - via the setCharacteristicNotification(). Are you using it? http://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#setCharacteristicNotification%28android.bluetooth.BluetoothGattCharacteristic,%20boolean%29 – barbazoo Oct 08 '13 at 13:15
  • I would have been really happy if I could read at least one charachteristic of an iOS device! I stucked much earlier, on the service discovery process. Please read all the comments and my edit section – edoardotognoni Oct 08 '13 at 15:29
  • I think in iOS there are limitations with bluetooth, you can check it here https://discussions.apple.com/message/8804276#8804276 – Pavan Jan 09 '14 at 07:12
  • I don't think that's the case. In that discussion they're talking about Bluetooth Classic, not BLE. – edoardotognoni Jan 10 '14 at 17:13
  • I know for a number of Android devices their initial connection interval is at 7ms and iOS doesn't want to communicate that quickly, it's bad for battery life so that could be one problem. – Douglas Jones Jan 10 '14 at 21:24
  • am also working on it @edoardotognoni will answer you soon, :) – Mandeep Apr 23 '14 at 06:35
  • thank you! Keep yourself updated on the Android bug page. Some guys were able to get charachteristics values, but it seems there are still some communication problems – edoardotognoni Apr 23 '14 at 08:03
  • Google has set the status of that bug to "obsolete". – ThomasW Apr 24 '15 at 08:43
  • "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. " Is this problem still there as of today (June 2017)? I tested with sample app from both App Store and Playstore, it seems to be the case. Not sure if there is any improvement not already done by those apps. – L.C. Tan Jun 23 '17 at 07:47

5 Answers5

7

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.

Community
  • 1
  • 1
Dominik Gebhart
  • 2,640
  • 1
  • 11
  • 27
  • Thanks, that works for me, note that in android M google have added an overload for the connectGatt method that takes a transport variable: connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport) – arbel03 Apr 07 '16 at 15:21
  • 1
    Oh thanks for this hint, so they made it aviable finally. – Dominik Gebhart Apr 07 '16 at 16:14
2

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.

omikes
  • 6,140
  • 8
  • 33
  • 44
2

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.

Roy Goode
  • 2,862
  • 18
  • 22
p2pkit
  • 1,049
  • 7
  • 10
1

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

Please see Android Documentation references below:

Kevin Crain
  • 1,775
  • 16
  • 27
0

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.