Cómo forzar mediante programación el descubrimiento de servicios bluetooth de baja energía en Android sin usar caché


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 BluetoothGatt.discoverServices(). Sin embargo, Android solo consulta el periférico una vez para descubrir servicios, las llamadas posteriores a discoverServices() dan como resultado los datos almacenados en caché de la primera llamada, incluso entre desconexiones. Si deshabilito/habilito el adaptador Android bt, discoverServices () actualiza la caché consultando el periférico. Existir ¿una forma programática de forzar a Android a actualizar su caché de servicios ble sin deshabilitar / habilitar el adaptador?

Author: benchuk, 2014-03-24

4 answers

Acabo de tener el mismo problema. Si ve el código fuente de BluetoothGatt.java puede 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 él. Pero en java tenemosreflexión , por lo que podemos acceder a este método. Aquí está mi código para conectar un dispositivo bluetooth actualizando la 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;
    }
 75
Author: Miguel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-30 17:28:09

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 Android y iPhone.

 2
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-29 15:28:02

Utilice 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.

 2
Author: Gyapti Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-20 09:40:39

En algunos Dispositivos, incluso si desconecta el socket, la conexión no terminará debido a la caché. Debe desconectar el dispositivo remoto mediante la clase BluetoothGatt. 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

 2
Author: Satheesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-05 09:49:48