android - things - bluetooth le devices
Bluetooth LE Scan no funciona en Android M en segundo plano (3)
Añadir 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 Pegar este método para solicitar y otorgar 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 verifica el permiso
if (Build.VERSION.SDK_INT >= 23) {
// Marshmallow+ Permission APIs
fuckMarshMallow();
}
Espero que ahorre su tiempo.
El siguiente código funciona muy bien en mi Nexus 9 con Android 5.1.1 (Build LMY48M), pero no funciona 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 del fabricante que coincide con el filtro de escaneo. (Vea el ejemplo de salida Logcat a continuación). 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 a ScanFilters funcionar en Android M?
El problema no era el filtro de escaneo, sino que el filtro de escaneo solo se usaba cuando la aplicación estaba en segundo plano. A partir de Android M, el escaneo de Bluetooth LE en segundo plano se bloquea a menos que la aplicación tenga uno de los dos permisos siguientes:
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. Al agregar el primero se resolvió 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
Consulte aquí para obtener más información: https://code.google.com/p/android-developer-preview/issues/detail?id=2964
Tuve un problema similar con una aplicación que se conecta a bluetooth. No LE ScanFilter, pero era un problema de permisos al igual que el OP tenía.
La causa principal es que a partir del SDK 23, debe solicitar al usuario los permisos en tiempo de ejecución utilizando el método requestPermissions()
.
Esto es lo que funcionó para mí:
Agregue una de las siguientes dos líneas 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" />
En su Actividad, antes de intentar conectarse a bluetooth, llame al método
requestPermissions()
, que abre un cuadro de diálogo del sistema para solicitarle al usuario el permiso. El cuadro de diálogo de permisos se abre en un hilo diferente, así que asegúrese de esperar el resultado antes de intentar conectarse a Bluetooth.Reemplace la
Activity
deonRequestPermissionsResult()
para manejar el resultado. Este método realmente solo necesitará hacer algo si el usuario se negó a otorgar el permiso, para decirle al usuario que la aplicación no puede hacer la actividad de bluetooth.
Esta publicación de blog tiene un código de ejemplo que utiliza AlertDialogs para decirle al usuario lo que está sucediendo. Es un buen punto de partida pero tiene algunas deficiencias:
- No controla la espera para que
requestPermissions()
elrequestPermissions()
- El AlertDialog que envuelve la llamada a
requestPermissions()
parece extraño. UnarequestPermissions()
llamada arequestPermissions()
es suficiente.