20

Il seguente codice funziona perfettamente sul mio Nexus 9 con Android 5.1.1 (Build LMY48M), ma non funziona su un Nexus 9 con Android 6.0 (Build MPA44l)Bluetooth LE ScanFilters non funzionano su Android M

Su Android 5.x, il codice sopra riportato restituisce una richiamata quando viene visualizzato un annuncio del produttore che corrisponde al filtro di scansione. (Vedere l'esempio di output Logcat di seguito.) Sul Nexus 9 con MPA44l, non si ricevono richiami. Se si commento il filtro di scansione, le richiamate vengono ricevuti con successo sul Nexus 9. ScanFilters

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} 

Qualcuno ha visto il lavoro su Android M?

+0

Avete bisogno di entrambi - NETWORK_PROVIDER e GPS_PROVIDER? O semplicemente NETWORK_PROVIDER. Maggiori informazioni qui: https://developer.android.com/guide/topics/connectivity/bluetooth-le.html –

risposta

16

Il problema non era il filtro di scansione, ma il filtro di scansione veniva utilizzato solo quando l'app era in background. A partire da Android M, Bluetooth LE scansione in background è bloccato a meno che l'applicazione ha uno dei seguenti due permesso:

android.permission.ACCESS_COARSE_LOCATION 
android.permission.ACCESS_FINE_LOCATION 

L'applicazione ero test non ha chiesto uno di questi permessi, in modo che non ha funzionato in lo sfondo (l'unica volta in cui il filtro di scansione era attivo) su Android M. Aggiungendo il primo si è risolto il problema.

ho capito che questo era il problema perché ho visto la seguente riga nel 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 

Vedi qui per maggiori dettagli: https://code.google.com/p/android-developer-preview/issues/detail?id=2964

+11

Ho aggiunto al mio manifest ma io visualizza il messaggio di errore: "java.lang.SecurityException: è necessario il permesso ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION per ottenere i risultati della scansione". Qualche idea su come risolvere questo? –

+5

A partire da Android 6, è necessario presentare anche una richiesta di autorizzazione a un usr in fase di runtime. Vedi qui per un esempio: http://developer.radiusnetworks.com/2015/09/29/is-your-beacon-app-ready-for-android-6.html – davidgyoung

+0

@davidgyoung quando do il permesso si ferma per la scansione fari. Per favore aiuta a uscire da questo problema. –

27

Ho avuto un problema simile con un app connessione a Bluetooth. Non LE ScanFilter, ma era un problema di permessi proprio come l'OP.

La causa principale è che, a partire dall'SDK 23, è necessario richiedere all'utente le autorizzazioni in fase di runtime utilizzando il metodo .

Ecco cosa ha funzionato per me:

  1. Aggiungere uno dei seguenti due righe per AndroidManifest.xml, all'interno del nodo principale:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
    
  2. Nella vostra attività, prima di tentare di collegare al bluetooth, chiamare il metodo Activity, che apre una finestra di dialogo di sistema per richiedere all'utente l'autorizzazione. La finestra di dialogo delle autorizzazioni si apre in un thread diverso, quindi assicurati di attendere il risultato prima di provare a connettersi al bluetooth.

  3. Ignora Activity 's onRequestPermissionsResult() per gestire il risultato. Questo metodo avrà davvero bisogno di fare qualcosa solo se l'utente si rifiuta di concedere l'autorizzazione, per dire all'utente che l'app non può fare l'attività Bluetooth.

This blog post ha qualche esempio di codice che utilizza AlertDialogs per dire all'utente che cosa sta succedendo.E 'un buon punto di partenza, ma ha alcuni difetti:

  • Non gestisce in attesa che il filo requestPermissions() per finire
  • L'AlertDialog avvolgendo la chiamata a requestPermissions() sembra estranea a me. È sufficiente una chiamata nuda a requestPermissions().
6

Aggiungi posizione permesso insieme a 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" /> 

Copia Incolla questo metodo per l'autorizzazione richiesta e posizione concessione

@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; 
    } 

E poi in scacco onCreate il permesso

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

Spero che risparmi tempo.

+1

Ha funzionato! Il nome della funzione però: p –