Jump to content
Rollo62

Howto handle Android BluetoothLE permissions that are compatible to API29,30,31 ?

Recommended Posts

Hi there,

 

I was experimenting with the Android.template.xml, to use different API-related selections, to searate old and new Bluetooth settings.

Some recommendations in the web point to this nice and clean solution, so separate APIs in the manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="...">

    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="30" />

    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" 
                     android:maxSdkVersion="30" />

    <application ... />

</manifest>

Using the android:maxSdkVersion and the android:usesPermissionFlags="neverForLocation" identifier would allow an easy control over different versions.

Unfortunately this didn't work in my current setup, maybe I have to rry again with a clean project, but I see a failure "attribute neverForLocation is not available".

This seems that targeting to API31 is needed, and I'm still under API30, in its D11 default setup.

 

But I'm not sure why this message pops up, and is not simply ignored, if there is an unknown attribute.

Probably this needs linked somehow to the API31, and API30 throws exception.

To be rescued, maybe the android:maxSdkVersion might work under different versions in different configurations, to make Delphi compatible with several API's at the same time in one manifest ?

 

To be clear, I'm not talking about the targetSdkVersion here, but if someone could make use of the  android:maxSdkVersion attribute already.

 

I'm curious if somebody has get this working as expected under Delphi.

 

Beside that, what would be the best way to handle BluetoothLE under API30, to be compatible with old and new devices ?

 

 

Share this post


Link to post

Has anyone solved this problem?  I have working apps with android:targetSdkVersion="32", but the UI is not very friendly.  It is asking for location permission, because you have to grant ACCESS_FINE_LOCATION, if you dont use the neverforlocation permission flag.  I have tested on Android 7,8,11 and 12.  Android 12 asks for location permission and shows to fine and coarse as an option.  If you select coarse, then BTLE will not work.  There are some other anomalies happening that i have not worked out yet.

 

Here is the uses-permisson portion generated by 11.2

 

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Share this post


Link to post

I have an app that uses Bluetooth LE and here's what I had to do to get it working on Android 12 (and above), as well as Android 11 and earlier. I am using RAD Studio 11.2 Alexandria.

 

1. Edit the AndroidManifest.template.xml file in the project directory to add a special entry for the BLUETOOTH_SCAN permission, so it looks like this:

 

....

    <uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
    <!-- for this next line to work, uncheck the "Bluetooth Scan" from projects "uses" options  -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<%uses-permission%>

....

NOTE: this is just a snippet from the template file showing the line I added, with a comment line above it.

 

2. In the project options dialog, edit the "Uses Permissions" section and remove the "Bluetooth Scan" option. This is necessary since that option is now already included in the manifest template, and if you select this option in the project options then RAD studio will add the bluetooth scan option to the output manifest, but WITHOUT the usesPermissionFlags attribute.

 

I have no idea if this is the best way to workaround this issue, but it works for me. I've tested it on devices running Android 10, 11, 12, and 13.

 

Hope this helps.

 

 

  • Like 1

Share this post


Link to post

I can confirm that this idea works.  I have actually taken it a step further using the template from the beginning of the thread as shown here

 

<%uses-permission%>
    <!-- for these next lines to work, uncheck from projects "uses" options  -->
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"  android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />

........

NOTE: as before this is just a portion of the template file

 

I have tested this on Android 8 and 12 so far and it works like I think it would.  Android 8 permission granting has not changed.  Android 12 now only asks to connect to nearby devices and to determine relative location.  I assume this is just the standard Android display for this.  Android 12 no longer asks about using the Phone's location, fine or coarse.  So this makes the user interface a lot cleaner.

 

What Delphi is missing is the ability to add these qualifiers to a permission.  That may be to hard to implement in clean way.  One downside to this approach, you need to save the template file.  Next Delphi upgrade will erase this template, so keep a copy.

 

Share this post


Link to post

@jcwhit

Yes its working, but I always have a bad feeling that it's not perfect for all versions.

I cannot really say, but I think it sometimes behaves odd on special devices.

 

To use a customized template is the way to go, sometimes I think about using a 100% custom template instead of the generated one, to have a much better control about the features.

Unfortunately the IDE has too many limits and causes hard-to-find errros, which could be easily fixes in a simple XML editor.

The urge to add too many automation and "smartness" in the IDE is not a good thing IMHO, I would prefer the pure textual options management over the checkbox-style.

I think Embarcadero should simply offer two ways for the options setting like this, maybe the UI way as-is,

plus a textual way, maybe through one JSON or XML file, alternatively.

This would be better integrate into CI and also easier to manage for humans and allow easier code reuse.

 

Maybe one day Embarcadero will consider my wish list, either allow both side-by-side or control one of both ways per selection in the tools options.

 

Share this post


Link to post

To get permission to access BLE, you must add some code to your program.

 

Please check:  ...Samples\Object Pascal\Multi-Device Samples\Device Sensors and Services\Bluetooth\BLEScanner

 

procedure TForm6.btnStartScanClick(Sender: TObject);
begin
  PermissionsService.RequestPermissions([FLocationPermission], RequestPermissionsResult, DisplayRationale);
end;

 

Share this post


Link to post

@pcplayer99

I'm afraid that alone won't do it for all versions of Android.

You will need more runtime permissions or other combinations of them, depending on the current OS version.

https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#java

Quote

The BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT, and BLUETOOTH_SCAN permissions are runtime permissions. Therefore, you must explicitly request user approval in your app before you can look for Bluetooth devices, make a device discoverable to other devices, or communicate with already-paired Bluetooth devices. When your app requests at least one of these permissions, the system prompts the user to allow your app to access Nearby devices, as shown in figure 1.

Thats why I still look after the "perfect" permission combination ( manifest and runtime ), which make Android happy for most older and newer Android versions.

Share this post


Link to post

The customized manifest file is working for me (see the snippet in my previous post), but on Android 10 and earlier I still have this problem:

 

1. App requests location permission at runtime, and the callback indicates that the permission is granted.

2. App then tries to make a Bluetooth connection to the device I'm trying to control (it's a laser with a Bluetooth UART module), and that all works, EXCEPT, if the user has turned off location services, then the app isn't able to connect. In the code I can't tell if it wasn't able to connect because the laser isn't on, or if it's because location services are off.

 

It seems like on Android 10 I can't make a Bluetooth connection unless location services are turned on? I guess even tho the system is telling me that the app has permission to use location (necessary to use Bluetooth on Android 10), it can't actually make a Bluetooth connection without it. My app doesn't need or use any location information -- I'm just using Bluetooth as a way communicating wirelessly with the laser and don't need (or want) to know any location info.

 

I guess that on Android 10 I can check to see if location services are enabled or not and ask the user to turn it on if needed, but that makes it seem like my app is tracking their location. Anyone run into this issue or have suggestions?

Share this post


Link to post
7 minutes ago, DelphiMT said:

It seems like on Android 10 I can't make a Bluetooth connection unless location services are turned on?

Yes, that was the case for older Android versions.

They considered that BLE can be tracked or used for tracking ( think of Beacons ) and therefor need a location permission.

Unfortunately they never invented a nearby location permission, but re-used the GPS one for this.

 

Share this post


Link to post

Thanks! Now I hate Bluetooth even more than before -- seems like it was implemented early on without much thought for privacy/security. At least it's handled better now in newer versions of Android.

Share this post


Link to post

Yes iOS was more stable and Android needed to catch up, but also in older versions it was stable since quite some time.

Remember Windows, also there BT was ( and is ) somewhat alien for a long time.

The biggest problem is that all OS permanently make changes in the permission system around the hardware, mainly because of GDPR.

This enforces still some sudden, hysteric implementations here and there, although I assumed this should be mature meanwile in the whole society for some time.

It looks to me that still there are no "best practices" how to handle GDPR in general, no matter for a sales slip in the bakery, for Cookies, for login to EU database, for medical devices, banking or software apps.

I'm looking forward for more creepy implementations to come in the future, its not all Android's or iOS's faults.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×