evothings / cordova-ble

Bluetooth Low Energy plugin for Cordova
http://www.evothings.com/
Apache License 2.0
242 stars 103 forks source link

cordova-ble does not work in android 6.0 due to change in permissions #87

Closed mogorman closed 8 years ago

mogorman commented 8 years ago

this is a bug in regards to android sdk version 23 change in permission model https://code.google.com/p/android-developer-preview/issues/detail?id=3055

when i rolled back target sdk version to 22 the ble code works fine.

fredrikeldh commented 8 years ago

The helpful folks over at Radius Networks have written an article explaining what needs to be done: http://developer.radiusnetworks.com/2015/09/29/is-your-beacon-app-ready-for-android-6.html

ghost commented 8 years ago

@fredrikeldh Thanks very useful article from Radius Networks.

More info about the MAC-address no longer is available: http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id

ghost commented 8 years ago

Investigate if permissions ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION need to be added.

See this forum post for error log: http://evothings.com/forum/viewtopic.php?f=8&t=2959

fenwick67 commented 8 years ago

Adding ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION didn't quite work for me... I still had to go into my device's Android settings and go to the app, then go into the app's permissions and toggle location services for it manually (Android M).

Somebody will need to go into the code and implement the request for location permission from the user, as the article @fredrikeldh linked to mentions.

requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); is how the permission is requested.

ghost commented 8 years ago

@fenwick67 Thanks for the update!

qpwr commented 8 years ago

@mikaelkindborg, do you have any information on when you think this will be fixed? Thanks a lot!

ghost commented 8 years ago

@qpwr Working on this now, hope to finish during the weekend :)

ghost commented 8 years ago

This is a bit crazy, but got something working now with Cordova 6 and Android 23.

Seems you must turn on Location in Settings as well as ask got location permissions for in the app:

http://stackoverflow.com/questions/33043582/bluetooth-low-energy-startscan-on-android-6-0-does-not-find-devices

Here is also useful info:

http://stackoverflow.com/a/33150570

Perhaps BluetoothLeScanner.startScan() should be used? And ACCESS_FINE_LOCATION?

http://stackoverflow.com/a/33052902

ACCESS_FINE_LOCATION rather than ACCESS_COARSE_LOCATION could be the key. Will try that. Tested with ACCESS_FINE_LOCATION, did not make any difference.

Only way I can make it work is by enabling Location in Settings in addition to the new code asking for location permission (this is done when start scanning).

Further info in this issue, indeed it seems Location has to be turned on by design for BLE scanning to work in Android 6.0:

https://code.google.com/p/android/issues/detail?id=189090&q=ble%20android%206.0&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

Another useful reply:

http://stackoverflow.com/a/33045489

ghost commented 8 years ago

Pushed a commit to master branch with the current state of the code: https://github.com/evothings/cordova-ble/commit/7b804c4bbd4570baab7d14aa462ccd07c02c9e5f

Note that for BLE scanning to work, Location has to be turned ON on Settings.

The plugin will in addition ask for Location permission for the app when startScan is called. Tested on Android 5.0 and Android 6.0.

Note that Cordova 6.x is now required to use the plugin.

Feedback and testing is welcome! :)

qpwr commented 8 years ago

WOW, very nice! Just to be sure: Do I have to check for any permissions manually in my app code? Or will the plugin do this for me?

ghost commented 8 years ago

@qpwr You don't have to check for app permissions manually from JavaScript code, that is done when calling startScan.

What do you think about this design? I was thinking about making a JavaScript call for asking for permissions, but then this would be Android only, and that is why I placed it in startScan.

qpwr commented 8 years ago

Well, I think I like it, but, to be honest with you, I'm not very into these things :-D

My only concern is to get my app running again on Android 6.0, because I've already released it with targetSdk 23, not being aware of the consequences :-(

Any advice on how I can add the master state as plugin into my app?

ghost commented 8 years ago

Just add the plugin like this:

cordova plugin add https://github.com/evothings/cordova-ble

If the plugin is already added, first remove it with:

cordova plugin rm cordova-plugin-ble

Let me know how it goes!

ghost commented 8 years ago

@qpwr If you want, you can join the Evothings Gitter channel: https://gitter.im/evothings/evothings It is a good place to ask questions and discuss IoT apps :)

qpwr commented 8 years ago

@mikaelkindborg, thanks for the advice, nice place :)

Just one more question: Will I have to tell my app users to turn on location settings or will there be any advice being shown to them so they know what they have to do?

qpwr commented 8 years ago

@mikaelkindborg, I've received testing feedback and it seems the current master state of your plugin is working fine on Android M as soon as the users turn on location services and give smartrace the permissions to use it. But, to be honest, it's very hard to convince users its necessary to turn on location services to make bluetooth work correctly :-(

Do you think there will probably another way to get it working without the need of this? But anyway, thanks a lot for adding this so fast! Keep up the great work, its much appreciated!

ghost commented 8 years ago

@qpwr Thanks for the encouragement!

Sadly, as far as I am aware the user has to turn on Location in the Settings app. I have not seen a smooth way to do this from code, but it would be possible to open the Settings app from the native plugin code. This should simplify for the user and lessen the risk of users dropping out of the app.

Here is a post that describes how to open the Setting app, will look into adding this to the plugin for the next release:

http://stackoverflow.com/a/33045489

ghost commented 8 years ago

Update:

With current BLE plugin 1.3 users will have to tell the users to enable Location in Settings for BLE to work on Android 6.

However, what can be done is opening the Settings app using an Intent. I am planning to add functions to the BLE JavaScript API to check if permissions are enabled and to turn them on, and to display the Settings app. This should make it possible to make it easier for users, since the app can direct users to the Settings app programatically.

This update is scheduled for next sprint "Garbo".

Aerue commented 8 years ago

HI what you means by "Garbo" ?

ghost commented 8 years ago

@Aerue Hi, thanks for asking. The Evothings sprints are named alphabetically, so "Garbo" is the name of the sprint. Next will be a name starting with "H" (I don't name the sprints!).

ghost commented 8 years ago

The problem with Android 6 permissions seems now to have been solved in version 1.3.2 of the BLE plugin. Fixed by this commit: https://github.com/evothings/cordova-ble/commit/1b664ca69e7f5c3759eeeaab9f988b4c54b06231

This update will be included in Evothings Viewer 1.4.1 for Android.

Closing issue. Let me know if problems persist.

ghost commented 8 years ago

Hello everyone,

I have revisited support for turning on system Location setting, in the Settings app. This is required on Marshmallow or higher.

What do you think of the solution implemented in this commit? https://github.com/evothings/cordova-ble/commit/b39da08b59f1fc56cbfe12c4f1318609a1d67a27

It displays a dialog if system Location is off (on Marshmallow or higher only) that allows the user to open the Settings app and turn Location on.

What do you think of the solution of making the plugin displaying this dialog? An alternative is to do this from JavaScript, but this would be specific functions for Android (check of Location is On, show Settings if not).

One thing would be to be able to localize strings used in the dialog. There could be a JavaScript function for that. See the actual dialog plugin code here: https://github.com/evothings/cordova-ble/blob/b39da08b59f1fc56cbfe12c4f1318609a1d67a27/src/android/BLE.java#L383

qpwr commented 8 years ago

@mikaelkindborg thanks for your effort on this!

To be very honest, I tend to dislike that showing the dialog (= affecting the UI) is part of the plugin. I would prefer some sort of sanity check which just delivers some information to my code and I can decide how to deal with it. E.g., there could be an init() method or the like exposed to JavaScript which I can use to check for these things (BT enabled, Location enabled, etc.). It would not need to be platform specific. All your code would do is to deliver the information. The plugin user can then decide how they want to deal with it.

I'm btw currently using https://www.npmjs.com/package/cordova.plugins.diagnostic in my project to check for certain things and react to them.

ghost commented 8 years ago

@qpwr Many thanks for the input! The diagnostics plugin looks very nice I must say. My thinking is that people who do not wish to write extra code would benefit from the built in UI.

There could be an option for disabling the built-in UI, and providing functions to handle permission checks etc from JavaScript. Alternatively handle it all from JS as you suggest.

DaniloCodecoCarvalho commented 8 years ago

Hi @mikaelkindborg.

Something weird happened to me. I had trouble with Android 6 too and realize that I was using version 1.3.0. So I updated to current 1.4.0 version just uninstalling with cordova plugin rm cordova-plugin-ble and installing with cordova plugin add https://github.com/evothings/cordova-ble.

Now Android 6 can connect to my BLE device but the data is no more collected.

So, to sum up: before I have a BLE that I can connect and read a vector in real time only in Android < 6. Now I have a BLE that I can connect in all Android versions but I can't read in all versions too.

Can you give me a hint? Thanks.

DaniloCodecoCarvalho commented 8 years ago

The version 1.4.1 solved my App @mikaelkindborg. Thank you very much.

Edited: In fact, now Android 6 works in the first run. But if I use evothings.ble.reset() when I change tabs, when I come back to the tab that uses BLE, it doesn't work again and the data is not collected :(

ghost commented 8 years ago

@DaniloCodecoCarvalho Normally you should not have to call reset(). It was implemented as a "last resort" for apps the reset BLE on Android. Early BLE implementations on Android were not very stable, thus reset() was implemented. This was a couple of years ago, modern Android versions are much more stable in my experience. Would it work to not call reset() in your app?

DaniloCodecoCarvalho commented 8 years ago

@mikaelkindborg In fact my app should connect a smartphone and a fitness equipment if the rssi between them is less than a determined value and keep connected only if this value doesn't change. The fitness equipment has a dock to allow the perfect distance (and rssi) between smartphone and equipment.

Thus, if user take the smartphone and walk away (change the rssi), the app will receive a batch of data from the fitness equipment and close the BLE connection. I tried to use close() but it didn't work.

However, if user come back and want to reconnect to the same fitness equipment 10 seconds later (a weird case but possible), the app should repeat scan and connection the same way as it did at the first time and this is the point where I can't figure it out. Once I have disconnected, I can't reconnect without call reset() and wait 15 or 20 seconds.

Sorry if my explanation was poor. I'm totally open to hear suggestions or better ideas, my app is not closed.

ghost commented 8 years ago

@DaniloCodecoCarvalho Thanks for the clarification, I understand the issue/use case now. Opened a new issue for this: https://github.com/evothings/cordova-ble/issues/108

ghost commented 8 years ago

Closing this issue now. Please let me know if to reopen, or just open an new issue if problems persist.

Status is that the plugin for Android asks for permissions if they are not granted, including the general Location setting. I know there are requests for making it possible to control this from JavaScript, and not automatically ask for permissions from native plugin code. This can be implemented, but we can make a new issue for this if this is considered high priority.