Android Bluetooth Código de baja energía compatible con API> = 21 Y API <21

Estoy desarrollando una aplicación que tiene que conectar con un dispositivo BLE, en mi código quiero usar el nuevo Scan y ScanCallback para BLE implementado desde API 21 (Android 5), pero tengo que mantener la compatibilidad con Android 4.3 y superior.

Así que escribí el código, por ejemplo, de esta manera:

if (Build.VERSION.SDK_INT >= 21) { mLEScanner.startScan(filters, settings, mScanCallback); } else { btAdapter.startLeScan(leScanCallback); } 

Y he definido las 2 callbacks, una para API 21 y superior y otra para API 18 a 20:

  //API 21 private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice btDevice = result.getDevice(); connectToDevice(btDevice); } public void connectToDevice(BluetoothDevice device) { if (mGatt == null) { mGatt = device.connectGatt(context, false, btleGattCallback); if (Build.VERSION.SDK_INT < 21) { btAdapter.stopLeScan(leScanCallback); } else { mLEScanner.stopScan(mScanCallback); } } } }; //API 18 to 20 private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { btAdapter.stopLeScan(leScanCallback); runOnUiThread(new Runnable() { @Override public void run() { mBluetoothGatt = device.connectGatt(context, false, btleGattCallback); } }); } }; 

También he añadido la anotación

 @TargetApi(21) 

Pero cuando lanzo la aplicación en Android 4.x se bloquea inmediatamente informando el error de que la clase ScanCallback no se puede encontrar (la que se pretende que se utiliza sólo con Android 5 y superiores).

¿Como puedo resolver esto?

Muchas gracias. Daniele.

Después de leer varios posts hice lo siguiente. Por si acaso, aquí está la documentación de Android sobre BluetoothLe

primero

Cree dos métodos uno scanLeDevice21 y scanLeDevice18 . En scanLeDevice21 agregue la anotación @RequiresApi(21) que dice:

Indica que el elemento anotado sólo debe ser llamado en el nivel de API dado o superior. Esto es similar en propósito a la anotación más antigua de @TargetApi, pero expresa más claramente que esto es un requisito en la persona que llama, en lugar de ser utilizado para "suprimir" las advertencias dentro del método que exceden a la minSdkVersion.

Segundo

Implementar cada método, aquí está mi código.

 @RequiresApi(21) private void scanLeDevice21(final boolean enable) { ScanCallback mLeScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); BluetoothDevice bluetoothDevice = result.getDevice(); if (!bluetoothDeviceList.contains(bluetoothDevice)) { Log.d("DEVICE", bluetoothDevice.getName() + "[" + bluetoothDevice.getAddress() + "]"); bluetoothDeviceArrayAdapter.add(bluetoothDevice); bluetoothDeviceArrayAdapter.notifyDataSetChanged(); } } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } }; final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(() -> { mScanning = false; swipeRefreshLayout.setRefreshing(false); bluetoothLeScanner.stopScan(mLeScanCallback); }, SCAN_PERIOD); mScanning = true; bluetoothLeScanner.startScan(mLeScanCallback); } else { mScanning = false; bluetoothLeScanner.stopScan(mLeScanCallback); } } /** * Scan BLE devices on Android API 18 to 20 * * @param enable Enable scan */ private void scanLeDevice18(boolean enable) { BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { bluetoothDeviceArrayAdapter.add(bluetoothDevice); bluetoothDeviceArrayAdapter.notifyDataSetChanged(); } }); } }; if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(() -> { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } } 

Tercero

Cada vez que necesite escanear dispositivos rodea su código preguntando qué versión es. Por ejemplo, tengo un RefreshLayout para mostrar la lista de dispositivos. Aquí está el resultado:

  /** * Refresh listener */ private void refreshScan() { if (!hasFineLocationPermissions()) { swipeRefreshLayout.setRefreshing(false); //Up to marshmallow you need location permissions to scan bluetooth devices, this method is not here since is up to you to implement it and it is out of scope of this question. requestFineLocationPermission(); } else { swipeRefreshLayout.setRefreshing(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scanLeDevice21(true); } else { scanLeDevice18(true); } } } 

Y eso es.

Olvídate de la extensión, las clases de subclase que realmente no necesita como respuesta ulusoyca.

  1. Cree la clase AbstractBluetoothLe y la interfaz IBleScanCallback . IBleScanCallback interfaz IBleScanCallback es una interfaz de marcadores. En otro dicho, una interfaz sin métodos. También puede agregar métodos a la interfaz si es necesario. Estos métodos harán la misma funcionalidad para todo tipo de scanCallbacks, es decir, getListOfFoundBleDevices (), clearListOfFoundBleDevices () etc.
  2. Crear BluetootLeLollipop , y BluetoothLeJellyBean clases que ampliar la clase AbstractBluetoothLe . Crea también BluetootLeMarshmallow clase BluetootLeMarshmallow que extiende BluetootLeLollipop clase BluetootLeLollipop . AbstractBluetoothLe clase AbstractBluetoothLe tiene el campo protegido mIBleScanCallback que es un objeto IBleScanCallback .
  3. Crear la clase BleScanCallbackBase que implementa IBleScanCallback .
  4. Cree la clase LollipopScanCallback que extiende la clase ScanCallback e implementa la interfaz IBleScanCallback . . Esta clase tiene un campo protegido scanCallback que será instanciado como BleScanCallbackBase objeto. Cree también la clase MarshmallowScanCallback que extiende la clase LollipopScanCallback .
  5. Cree una clase JellyBeanScanCallback que extienda BleScanCallbackBase e implemente BluetoothAdapter.LeScanCallback
  6. En BleScanCallbackBase anular el método: onScanCallback(...)
  7. En LollipoScanCallback anula onScanResult(int callbackType, ScanResult result) y dentro de este método llama al método onScanCallback(...) del objeto scanCallback .
  8. En JellyBeanScanCallback anula onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) y dentro de este método llame a onScanCallback(...)
  9. Por último, haga lo que sea necesario cuando se encuentra un dispositivo en el onScanCallback(...) de la clase BleScanCallbackBase .

En resumen, lea acerca de la composición sobre la herencia, sé que esto no es una respuesta a su pregunta, pero esta es una manera ordenada de lo que desea lograr al final. Aquí está el diagrama de la clase: introduzca la descripción de la imagen aquí

Su código se está bloqueando porque está creando una clase interna anónima. Por lo tanto, en tiempo de ejecución no encuentra que sCanCallback clase.

Intente abajo y comparta el resultado. Antes de intentar esto, asegúrese de comentar la devolución de llamada (ScanCallback).

  if (Build.VERSION.SDK_INT >= 21) { mLEScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice btDevice = result.getDevice(); connectToDevice(btDevice); } public void connectToDevice(BluetoothDevice device) { if (mGatt == null) { mGatt = device.connectGatt(context, false, btleGattCallback); if (Build.VERSION.SDK_INT < 21) { btAdapter.stopLeScan(leScanCallback); } else { mLEScanner.stopScan(mScanCallback); } } } }; } else { btAdapter.startLeScan(leScanCallback); } 
  • Si se crea un vínculo con un dispositivo Bluetooth LE
  • Seguridad de emparejamiento BLE
  • Android Bluetooth Baja energía a veces bloqueo
  • Estado de Android Bluetooth 133 en gatt.readCharacteristic
  • Bluetooth de baja energía para Samsung Galaxy S3 y TI CC2540 monitor de ritmo cardíaco
  • Análisis BLE de Android en el servicio de fondo
  • BluetoothGatt writeCharacteristic devuelve false
  • Lea las notificaciones cuando toque el botón en el dispositivo BLE
  • ¿Cómo utilizar la API de bloqueo inteligente en mi aplicación para desbloquear el modo de patrón?
  • El dispositivo Android BLE recibe resultados extremadamente irregulares
  • Cómo solucionar el error BluetoothGatt: android.os.DeadObjectException error en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.