Bluetooth LE ScanFilters no funciona en Android M

El código siguiente funciona muy bien en mi Nexus 9 con Android 5.1.1 (Build LMY48M), pero no funcionará en un Nexus 9 con Android 6.0 (Build MPA44l)

List<ScanFilter> filters = new ArrayList<ScanFilter>(); ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build(); ScanFilter.Builder builder = new ScanFilter.Builder(); builder.setManufacturerData((int) 0x0118, new byte[]{(byte) 0xbe, (byte) 0xac}, new byte[]{(byte) 0xff, (byte)0xff}); ScanFilter scanFilter = builder.build(); filters.add(scanFilter); mBluetoothLeScanner.startScan(filters, settings, new ScanCallback() { ... }); 

En Android 5.x, el código anterior produce una devolución de llamada cuando se ve un anuncio de fabricante que coincide con el filtro de exploración. (Vea el ejemplo de salida de Logcat más abajo.) En el Nexus 9 con MPA44l, no se reciben devoluciones de llamada. Si comenta el filtro de exploración, las devoluciones de llamada se reciben correctamente en el Nexus 9.

 09-22 00:07:28.050 1748-1796/org.altbeacon.beaconreference D/BluetoothLeScanner﹕ onScanResult() - ScanResult{mDevice=00:07:80:03:89:8C, mScanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={280=[-66, -84, 47, 35, 68, 84, -49, 109, 74, 15, -83, -14, -12, -111, 27, -87, -1, -90, 0, 1, 0, 1, -66, 0]}, mServiceData={}, mTxPowerLevel=-2147483648, mDeviceName=null], mRssi=-64, mTimestampNanos=61272522487278} 

¿Alguien ha visto ScanFilters trabajar en Android M?

Tuve un problema similar con una aplicación de conexión a bluetooth. No LE ScanFilter, pero era un problema de permisos igual que el OP.

La causa raíz es que a partir del SDK 23, debe solicitar al usuario permisos en tiempo de ejecución mediante el método requestPermissions() .

Esto es lo que funcionó para mí:

  1. Añada una de las dos líneas siguientes a AndroidManifest.xml , dentro del nodo raíz:

     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
  2. En su actividad, antes de intentar conectarse al bluetooth, llame al método requestPermissions() , que abre un diálogo del sistema para solicitar al usuario el permiso. El diálogo de permisos se abre en un hilo diferente, así que asegúrese de esperar el resultado antes de intentar conectarse al bluetooth.

  3. onRequestPermissionsResult() Activity onRequestPermissionsResult() para manejar el resultado. Este método realmente sólo tendrá que hacer algo si el usuario se negó a conceder el permiso, para decirle al usuario que la aplicación no puede hacer la actividad bluetooth.

Esta entrada del blog tiene algún código de ejemplo que utiliza AlertDialogs para decirle al usuario lo que está pasando. Es un buen punto de partida pero tiene algunas deficiencias:

  • No controla la espera para que el requestPermissions() termine
  • El AlertDialog que envuelve la llamada a requestPermissions() parece extraño. Una requestPermissions() llamada a requestPermissions() es suficiente.

El problema no era el filtro de escaneo, sino que el filtro de escaneado sólo se utilizaba cuando la aplicación estaba en segundo plano. A partir de Android M, la exploración Bluetooth LE en segundo plano está bloqueada a menos que la aplicación tenga uno de los siguientes dos permisos:

 android.permission.ACCESS_COARSE_LOCATION android.permission.ACCESS_FINE_LOCATION 

La aplicación que estaba probando no solicitó ninguno de estos permisos, por lo que no funcionó en segundo plano (la única vez que el filtro de escaneo estaba activo) en Android M. La adición de la primera solucionó el problema.

Me di cuenta de que este era el problema porque vi la siguiente línea en Logcat:

 09-22 22:35:20.152 5158 5254 E BluetoothUtils: Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results 

Consulta aquí para obtener más información: https://code.google.com/p/android-developer-preview/issues/detail?id=2964

Agregar permiso de ubicación junto con BLE

 <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 

Copiar Pega este método para solicitar y conceder permiso de ubicación

  @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: { Map<String, Integer> perms = new HashMap<String, Integer>(); // Initial perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED); // Fill with results for (int i = 0; i < permissions.length; i++) perms.put(permissions[i], grantResults[i]); // Check for ACCESS_FINE_LOCATION if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) { // All Permissions Granted // Permission Denied Toast.makeText(ScanningActivity.this, "All Permission GRANTED !! Thank You :)", Toast.LENGTH_SHORT) .show(); } else { // Permission Denied Toast.makeText(ScanningActivity.this, "One or More Permissions are DENIED Exiting App :(", Toast.LENGTH_SHORT) .show(); finish(); } } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } @TargetApi(Build.VERSION_CODES.M) private void fuckMarshMallow() { List<String> permissionsNeeded = new ArrayList<String>(); final List<String> permissionsList = new ArrayList<String>(); if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION)) permissionsNeeded.add("Show Location"); if (permissionsList.size() > 0) { if (permissionsNeeded.size() > 0) { // Need Rationale String message = "App need access to " + permissionsNeeded.get(0); for (int i = 1; i < permissionsNeeded.size(); i++) message = message + ", " + permissionsNeeded.get(i); showMessageOKCancel(message, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); } }); return; } requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); return; } Toast.makeText(ScanningActivity.this, "No new Permission Required- Launching App .You are Awesome!!", Toast.LENGTH_SHORT) .show(); } private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(ScanningActivity.this) .setMessage(message) .setPositiveButton("OK", okListener) .setNegativeButton("Cancel", null) .create() .show(); } @TargetApi(Build.VERSION_CODES.M) private boolean addPermission(List<String> permissionsList, String permission) { if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { permissionsList.add(permission); // Check for Rationale Option if (!shouldShowRequestPermissionRationale(permission)) return false; } return true; } 

Y luego en onCreate cheque por permiso

  if (Build.VERSION.SDK_INT >= 23) { // Marshmallow+ Permission APIs fuckMarshMallow(); } 

Espero que ahorrar su tiempo.

  • ¿Es posible conectar el dispositivo Android Wear con otro dispositivo BLE directamente sin interacción del dispositivo telefónico?
  • ¿La API de Android 20 permite que los dispositivos compatibles con Bluetooth LE actúen como un dispositivo periférico?
  • Detectar AC (encendido / apagado) y Ventana (abrir / cerrar) de CAR utilizando OBD
  • ¿Por qué el "" BluetoothAdapter: startLeScan (): null "" ocurrió cuando BLE Scan en Android?
  • La devolución de llamada de Gatt de BLuetooth no funciona con la nueva API de Lollipop
  • El dispositivo Android BLE recibe resultados extremadamente irregulares
  • Error Android Bluetooth LE: Error al registrar la devolución de llamada
  • Bluetooth Low Energy startScan en Android 6.0 no encuentra dispositivos
  • OnServicesDiscovered es 129 y se conecta inestable para BLE en Android
  • Bluetooth GATT - onServicesDiscovered (BluetoothGatt gatt, estado int) no contiene todos los servicios
  • La exploración de dispositivos Android BLE con filtro no funciona
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.