Gestione dei permessi delle app in Android 6 Marshmallow

Posted by RedBlue on February 06, 2016 · 4 mins read

In Android 6 una delle innovazioni più rilevanti (anche a livello di sviluppo) è la gestione dei permessi delle app. Avete presente? Parliamo di quella lista di autorizzazioni (accesso ai contatti, alla fotocamera, alla rete, allo storage, etc) che quasi ogni app presentava in fase di installazione, e che bisognava accettare per proseguire l'installazione stessa (a dire il vero, tale lista nella maggior parte dei casi veniva completamente ignorata).

Android

Adesso la musica è cambiata, non c'è più il listone di permessi in fase di installazione, ma l'app dovrà presentare all'utente la richiesta di accedere ad una determinata funzionalità solo quando questa si renderà necessaria (ovvero a runtime). L'utente può decidere se concedere l'autorizzazione (in tal caso non ci sarà più alcuna richiesta per quella caratteristica) oppure no. Inoltre, nelle impostazioni dell'app, c'è la lista dei permessi concessi, con la possibilità di revocarli.

Dal punto di vista dello sviluppatore, questo comporta un'aggiunta di codice, necessaria ad implementare questa nuova gestione. Ovviamente, i permessi necessari vanno sempre dichiarati nell'AndroidManifest.xml, ad esempio, considerando i servizi di localizzazione, dovremo aggiungere la riga:

A questo punto, nell'activity che stiamo realizzando, sarà necessario gestire la richiesta, potremmo ad esempio usare del codice simile a questo:

if (Build.VERSION.SDK_INT >= 23 &&

                    ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED {

                Log.i(TAG, "Verifica permessi per la localizzazione");

                requestLocationPermission();

            } else {

                Log.i(TAG, "Permessi di accesso alla localizzazione già concessi");

                accessMap();

            }

Come si vede, in caso di versione delle API a partire dalla 23 (Android M), verrà chiamato il metodo checkSelfPermission(context, permission) sul permesso in questione. I due metodi requestLocationPermission() e accessMap() sono semplicemente due implementazioni che ho realizzato per gestire la richiesta e per visualizzare la mappa (rispettivamente). Vediamo il primo:

private void requestLocationPermission() {

        Log.i(TAG, "Richiesta permessi per la LOCALIZZAZIONE");

        if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION)) {

            Snackbar.make(mLayout, R.string.permission_location, Snackbar.LENGTH_INDEFINITE).setAction(R.string.permission_location_go, new View.OnClickListener() {

                @Override

                public void onClick(View v) {
&&
                    ActivityCompat.requestPermissions(MapTorneiActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION);

                }

            }).show();

        } else {

            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION);

        }

    }

Questo metodo serve appunto a presentare all'utente la richiesta di accesso al sistema di localizzazione del terminale, permesso che l'utente potrà concedere o meno (ovviamente in quest'ultimo caso, la parte della nostra app che richiede l'uso della localizzazione non funzionerà).

Infine, è possibile anche sfruttare un metodo di callback, che eseguirà determinate operazioni in base alla risposta dell'utente:

@Override

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        Log.i(TAG, "Risposta dell\'utente alla richiesta di accesso alla localizzazione");

        if (requestCode == REQUEST_LOCATION) {

            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                Snackbar.make(mLayout, R.string.permission_location_ok, Snackbar.LENGTH_SHORT).show();

                accessMap();

            } else {

                Snackbar.make(mLayout, R.string.permission_location_no, Snackbar.LENGTH_SHORT).show();

            }

        } else {

            super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        }

    }

Con questo metodo, se l'utente concede l'autorizzazione, viene richiamato accessMap() che imposta e visualizza la mappa, altrimenti un messaggio avvisa che l'autorizzazione non è stata concessa (la mappa verrà ugualmente visualizzata, ma ovviamente non sarà visibile nulla di ciò che la nostra app dovrebbe fare.

L'implementazione del metodo accessMap() esula dall'argomento trattato in questo post, ma si tratta fondamentalmente di un metodo che gestisce le impostazioni di visualizzazione della mappa e attiva la ricerca della posizione del terminale.

In ultimo, se nell'app si trovano altre chiamate che potrebbero necessitare di permessi, per ognuna di essere va implementata una gestione simile a quella vista, o in alternativa si può scegliere di gestire per intero la chiamata "principale", andando a racchiudere in un blocco try.. catch le altre chiamate, in modo da poter almeno sollevare una SecurityException in caso di mancanza del relativo permesso. Resta inteso che se l'app mantiene una retrocompatibilità con versioni precedenti di Android, la gestione dei permessi resta quella a cui eravamo abituati.

Alla prossima..