missing serviceUUIDs on android 12
I was now forced by google to increase my target api level for android to 31 (android 12).
After fixing the permission problems (with help from 2 closed issues, a readme update would be nice), the scan started like before but didn't yield any results.
Removing the filter by serviceUUID from scan options did get me results again, but trying to read the service uuid list gets me an empty array.
All this with the latest versions of nativescript, ble module, ...
@ray007 you are welcome to create a PR for the doc
as for the rest without more details i cant really help you we are using native apis to get serviceUUIDs from advertisment data https://developer.android.com/reference/android/bluetooth/le/ScanRecord#getServiceUuids().
as we are to set the filter https://developer.android.com/reference/android/bluetooth/le/ScanFilter.Builder#setServiceUuid(android.os.ParcelUuid
You can add console logs to the android file of the ble plugin to see where it is failing
Anyone any idea what needs to be done to read serviceUUIDs again or filter by some on android 12+ ?
@ray007 maybe debug it , add logs to see what s happening and where it fails ;)
Hmm, I followed things down to ScanCallBackImpl.prototype.onScanResult (around line 475 in bluetooth.android.js).
The property mServiceUuids of the ScanRecord is null.
Ignoring this and trying to read the characteristic anyway also does not work:
[BluetoothError]:error_function_call, readCharacteristic, [B@e4a57a1, {"peripheralUUID":"EB:38:0B:BE:FD:D7","serviceUUID":"78a90000-26ce-4367-bfeb-7e3c1d217561","characteristicUUID":"78a90001-26ce-4367-bfeb-7e3c1d217561","timeout":1000}
@ray007 there is no mServiceUuids variable in the plugin. on post lollipop Service uuids are directly recovered from a native object https://github.com/nativescript-community/ble/blob/70545002b3b9f8ae0d749aec912dc6d9ec092e0b/src/bluetooth.android.ts#L643.
Yes, but when dumping a ScanRecord with console.log, you can see the mServiceUuids property.
The funny things also is, I can see a serviceUUID there from one garmin device.
Talking to our sensor developer, it seems there's the advertisement and then a second 'scan response' message? And since the serviceUuids of our sensors are in the second message they seem to be missing after setting the target api level to 31...
@ray007 something bugs me in what you are saying.ScanRecord is a native object (android.bluetooth.le.ScanRecord) so the mServiceUuids should not be printed. even if it shows you a mServiceUuids you should (to debug) try to console log using native methods https://developer.android.com/reference/android/bluetooth/le/ScanRecord#getServiceUuids()
Now about your double message thing i didnt know it was possible. Now the thing is the ble plugin does not send duplicate events for discovery. which might be your issue https://github.com/nativescript-community/ble/blob/384afba16e8eb029e4e8d5077bdf67eaadd4ffa7/src/bluetooth.android.ts#L475 You can try to remove the if test. If it works you are welcome to create a PR for a scanning parameter to allow duplicate events (default to false to be retro compatible).
Looking at https://docs.particle.io/reference/device-os/api/bluetooth-le-ble/blepeerdevice/#blescanresult, there seems to be a scanResponse separate from the advertisingData, which needs an extra request but no connect.
And starting with api level 31 on android, this extra data apparently does not get retrieved anymore.
It's much harder to read in the Bluetooth Core Specification 5.2, but Volume 3, Part C, Chapter 11 Advertising and Scan Response Data Format (page 1392) and Volume 4, Part E, Chapter 7.8.8 LE Set Scan Response Data command (page 2489) should hold the relevant information.
@ray007 good catch! Have you tried to remove the if i talked about to see if there was not a second "event" with the extra data? Edit : we can continue that discussion on discord until we find the solution
Unfortunately no.
But on my test device, the code path does not seem to go through this onLeScan function, but through a similar method ScanCallBackImpl#onScanResult.
The stateObject check there is only a get or create.
Since the problem only happened upon increasing the targetApi level with the same ble module code, I suspect, that the problem is somewhere on a lower level in the java api. I had hoped that it might just need an extra flag/option/... to be set somewhere, but looking at android docs I have found nothing so far.
@ray007 yes it depends on the OS version. It uses one or the user if os version is pre or post lolippop
Yes it is an issue in android itself but we might be able to fix it. You need to be able to test on android 31 or more though
My question on stackoverflow hasn't got any responses so far. Maybe we need to file a bugreport somewhere with the android project...
This might help
https://github.com/nativescript-community/ble/issues/261
I'm reading without a problem on Android 12 (API 31) now. I'm using nativescript-vue, and to debug, I output the JSON with:
<TextView class="theDevice" editable="false" maxLines="3">
{{ currentDevice.json }}
</TextView>
Where I populate the json property with "json: JSON.stringify(perip)". So, I can see all the service UUIDs on the device after populating perip.services from a call to discoverServices. Note that I do not get them on connect, per my original issue.
@erik777 Thanks for trying, but no luck so far.
But I tried to call discoverServices({peripheralUUID:peripheral.UUID}) in my onDiscovered callback during the scan, not in onConnected like you did.
Calling discoverServices like this on the bluetooth instance I'm also using to call startScanning(args) on results in an error:
[BluetoothError]:Cannot read property 'discoverServices' of undefined, discoverServices, undefined, {"peripheralUUID":"F2:D7:ED:2E:D9:80"}
Note: I also checked with nRF Connect, and there I also can only see the services when I do a connect, not before.
Did something get broken in Android with newer API levels?
Update: trying to ignore the problem at scan-time and just trying to connect and read the characteristic does not work either:
[BluetoothError]:error_function_call, readCharacteristic, [B@9abe29b, {"peripheralUUID":"EB:38:0B:BE:FD:D7","serviceUUID":"78a90000-26ce-4367-bfeb-7e3c1d217561","characteristicUUID":"78a90001-26ce-4367-bfeb-7e3c1d217561","timeout":1000}
@ray007 if you want to check it out, I got it all working in this app
https://github.com/erik777/fun/tree/main/nativescript/osBT-ts
Runs on Android 12 and 11. Note I had to do things with permissions in the beginning, which can be your issue. There were definitely major permission changes in BLE in Android 12. I've seen a lot of app devs struggle with this in other discussions. But, I did finally get it where you just have to accept the popups on first run and no longer have to navigate to settings to explicitly give it permission. I think other devs had a hard time figuring that one out so they throw up an upset dialog then send the user to the system settings lol.
You can run the app, but the part where it reads/writes it is specific to my RoboSmart lightbulbs. I debug by appending to text boxes. That's how I reverse engineer what it returns as I develop, and how I got services working.
Note that I never discover characteristics because I knew them in advance. So, can't verify if that query works. But, have no trouble reading/writing to them.
Here's where I defined characteristic IDs for my light bulbs.
https://github.com/erik777/fun/blob/main/nativescript/osBT-ts/app/shared/RoboSmart.ts
I did have to discover services, though, even though I had them in advance, as well. That does work.
@erik777 thanks for trying to help.
I don't think permissions are the problem. I know those have changed but updating for that was quite easy.
I also do find our sensors and other devices during a scan, but not if I try to filter by serviceUUID.
Question: does your hardware send the serviceUUIDs in the advertisingData, or in an extra scanResponse?
@ray007 so far I have only seen in the discoverServices response. I have yet to see advertisingData populated, but also haven't considered it, so not sure when it is supposed to populate.