permisos - Cómo forzar programáticamente el descubrimiento del servicio de baja energía del bluetooth en Android sin usar el caché
nivel de api 26 (4)
De hecho, la respuesta de Miguel funciona. Para usar refreshDeviceCache, tengo éxito con este orden de llamada:
// Attempt GATT connection
public void connectGatt(MyBleDevice found) {
BluetoothDevice device = found.getDevice();
gatt = device.connectGatt(mActivity, false, mGattCallback);
refreshDeviceCache(gatt);
}
Esto funciona para OS 4.3 a 5.0 probado con periféricos de Android y iPhone.
Estoy usando Android 4.4.2 en un Nexus 7. Tengo un periférico bluetooth de baja energía cuyos servicios cambian cuando se reinicia. La aplicación para Android llama a BluetoothGatt.discoverServices (). Sin embargo, Android solo consulta el periférico una vez para descubrir los servicios, las llamadas subsiguientes a discoverServices () dan como resultado los datos almacenados en caché desde la primera llamada, incluso entre las desconexiones. Si deshabilito / habilito el adaptador Android bt, discoverServices () actualiza la caché consultando el periférico. ¿Existe alguna forma programática para obligar a Android a actualizar su caché de servicios ble sin desactivar / habilitar el adaptador?
En algunos dispositivos, incluso si desconecta el socket, la conexión no finalizará debido a la caché. Debe desconectar el dispositivo remoto utilizando la clase BluetoothGatt. Como a continuación
BluetoothGatt mBluetoothGatt = device.connectGatt(appContext, false, new BluetoothGattCallback() {
};);
mBluetoothGatt.disconnect();
Nota: Esta lógica funcionó para mí en dispositivos basados en China
Use lo siguiente antes de escanear el dispositivo:
if(mConnectedGatt != null) mConnectedGatt.close();
Esto desconectará el dispositivo y borrará la caché y, por lo tanto, podrá volver a conectarse al mismo dispositivo.
Acabo de tener el mismo problema. Si ves el código fuente de BluetoothGatt.java , puedes ver que hay un método llamado refresh ()
/**
* Clears the internal cache and forces a refresh of the services from the
* remote device.
* @hide
*/
public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
try {
mService.refreshDevice(mClientIf, mDevice.getAddress());
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
Este método realmente borra la caché de un dispositivo bluetooth. Pero el problema es que no tenemos acceso a eso. Pero en Java tenemos reflection , entonces podemos acceder a este método. Aquí está mi código para conectar un dispositivo bluetooth refrescando el caché.
private boolean refreshDeviceCache(BluetoothGatt gatt){
try {
BluetoothGatt localBluetoothGatt = gatt;
Method localMethod = localBluetoothGatt.getClass().getMethod("refresh", new Class[0]);
if (localMethod != null) {
boolean bool = ((Boolean) localMethod.invoke(localBluetoothGatt, new Object[0])).booleanValue();
return bool;
}
}
catch (Exception localException) {
Log.e(TAG, "An exception occured while refreshing device");
}
return false;
}
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG,"BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothGatt != null) {
Log.d(TAG,"Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the
// autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(MyApp.getContext(), false, mGattCallback));
refreshDeviceCache(mBluetoothGatt);
Log.d(TAG, "Trying to create a new connection.");
return true;
}