We are using the Android-BLE-library version 2.1.1 above Android 9 (API level 28, using Java 8) in order to connect to a BLE-MCU. This MCU advertises a custom BLE profile.
When trying to connect with the nRF-Connect application, we succeed in finding the MCU, connecting to it, pairing and discovering the service's characteristics, reading and writing to them.
However, when we try to discover the characteristics using the BLE-Library within our app, we usually fail to fetch the characteristics.
The process our app does is:
Scanning for the device using Android's scanner, using the service UUID as filter.
Connecting to the device using:
mDevBleManager.connect(mDevInfo.getDevice()) .done(device -> Log.i(logTag, "Connected to device: " + device.getAddress())) .enqueue();
On the callback OnDeviceConnected we create a bond using:
Request bond_req = this.createBond(); bond_req.done(device -> Log.i(logTag, "bond successful")) .fail((device, status) -> Log.w(logTag,"bond failed: " + status)) .enqueue();
And inside of our extension of BleManager.BleManagerGattCallback we implemented the following:
@Override protected boolean isRequiredServiceSupported(@NonNull BluetoothGatt gatt) { Log.i(logTag, "Fetching the characteristics from the service"); final BluetoothGattService service = gatt.getService(serviceUUID); if (service != null) { mChar1 = service.getCharacteristic(char1UUID); mChar2 = service.getCharacteristic(char2UUID); mChar3 = service.getCharacteristic(char3UUID); mChar4 = service.getCharacteristic(char4UUID); mChar5 = service.getCharacteristic(char5UUID); } boolean wasSuccessful = (mChar1 != null && mChar2 != null && mChar3 != null && mChar4 != null && mChar5 != null); if (!wasSuccessful) { Log.e(logTag, "fetching the characteristics failed"); } else { Log.i(logTag, "successful fetch"); } return wasSuccessful; }
We expect this to be called, however, most of the time, we don't get into this function after connecting. When trying to write into the last characteristic (mChar5), we get on the fail callback the status REASON_NULL_ATTRIBUTE. On some rare cases, we do get the characteristics before trying to write or read from them (for example, in the initialize method of BleManager.BleManagerGattCallback, similar to the usage in the nRF Toolbox), however, usually we end up with a failed request (and it takes a while to invoke the fail callback of the read/write).
In order to read we use the following code:
byte[] data = /* some data calculations */ ; writeCharacteristic(mPhoneMsgChar, encodedMsg) .before(dev -> Log.d(logTag, "Enqueue write request")) // this is being printed .done(dev -> Log.i(logTag, "written")) // this is usually not! .fail((device, status) -> Log.w(logTag,"failed due to: " + status)) // getting with a long delay .enqueue();
Also, it does not always succeed in pairing, at least not in a feasible time (the MCU rejects it after a timeout).
We will appreciate any help on this subject!