View
logo
logo

Contatti

Labs Sviluppo Software 17 Febbraio 2020

La richiesta dei permessi di Android

Writen by odc-admin

comments 0

LAB_image_05
Se mi fermo a pensare riesco a vedere ogni singolo sviluppatore Android che ha perso almeno mezz’ora del suo tempo a cercare di capire “…ma come mai non mi funziona questo!?!?“, oppure “… ma come mai non mi funziona quello?!??“. Risposta: cavolo, i permessi!!!
Il mondo delle autorizzazioni e permessi di Android è un sistema che, come tutti gli altri meccanismi peculiari di questa piattaforma del resto, va digerito in modo completo.
Bando alle ciance!
Negli anni mi sono creato un flusso abbastanza preciso per richiedere i permessi che, bene o male funziona per tutti i casi. Seguendo questi passi, non dovreste avere problemi:
A voi lo spiegone:
All’apertura dell’Activity, o Fragment, o quando è necessario per la vostra App (ad es. quando viene eseguito un click sul pulsante della fotocamera), invocate un metodo che controlla subito i permessi (esempio un checkPermissions()
Il metodo seguirà questi passi:
  1. La mia App ha i permessi?
    1. SI: (es. ) mostra la posizione dell’utente sulla mappa, oppure (altro esempio) mostra il bottone “Scatta foto”
    2. NO:  in questo ramo andremo a controllare se c’e’ bisogno di mostrare il Dialog per la richiesta ulteriore di permessi, perche’ l’utente l’ha negata prima in modo non definitivo. Qui ci viene in aiuto il metodo , shouldShowRequestPermissionRationale() del Context o ActivityCompat
      1. Se c’è bisogno di mostrarlo, lo faro’, dando una spiegazione sul fatto che avendo negato i permessi precedentemente la mia App non potrà utilizzare certe funzionalità, dando una ulteriore possibilità di concessione di permessi
      2. Se non cè bisogno di Rationale allora andremo direttamente a richiedere i permessi con il dialog di sistema.
Ora, provo a tradurre in codice quello che ho descritto dettagliatamente nei punti qui sopra.
fun checkPermissions() {
    // Controlliamo se i permessi sono stati concessi...
    if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {

        // Permessi non concessi
        // Dobbiamo mostrare una spiegazione?
        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            // Mostra una spiegazione del perchè la mancanza di questi permessi
            // può negare alcune funzionalità. Questa spiegazione può essere
            // data con un semplice AlertDialog(). Alla riposta positiva (l'utente
            // accetta di dare i permessi) andremo a richiedere i permessi con
            // le istruzioni predefiniti (es. ActivityCompat.requestPermissions([...])
            // come mostrato qui sotto
        } else {
            // Nessuna spiegazione da dare, richiediamo direttamente i permessi
            ActivityCompat.requestPermissions(thisActivity,
                    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                  REQUEST_LOCATION_PERMISSIONS)

            //REQUEST_LOCATION_PERMISSIONS è una costante che andremo ad utilizzare
            // nel metodo onRequestPermissionsResults([...]) per analizzare i risultati
            // ed agire di conseguenza
        }
    } else {
        // Fantastico, abbiamo già i permessi, possiamo fare tutti i danni che vogliamo :D
    }
}

Il flusso che vi ho descritto qua sopra può essere considerato abbastanza “standard”, ovvero può adattarsi a qualsiasi tipo di permesso. Il concetto, per concludere, è piuttosto semplice, quindi: Ho i permessi? Si: faccio le mie cose. No? Guardo se devo richiederli di nuovo, altrimenti mi rassegno ?

Ultimo e non ultimo, il metodo

override fun onRequestPermissionsResults([...])

… in cui andremo ad esaminare se i permessi sono stati concessi ed eventualmente attivare / disattivare / far partire alcune funzionalità

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        REQUEST_LOCATION_PERMISSIONS -> {
            map?.uiSettings.isMyLocationButtonEnabled = false
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                button_position_on_me.visibility = View.VISIBLE
                map.isMyLocationEnabled = true
            } else {
                button_position_on_me.visibility = View.GONE
                map.isMyLocationEnabled = false
                Snackbar.make(
                    view!!,
                    getString(R.string.gps_permissions_not_granted),
                    Snackbar.LENGTH_INDEFINITE
                )
                    .setAction(android.R.string.ok) {
                        checkLocationPermissions()
                    }
                    .show()
            }
        }
    }
}
In questo esempio, preso da un’applicazione reale che *MODALITA’ EGO ENORME ON* ha sulle spalle centinaia di migliaia di installazioni attive *MODALITA’ EGO ENORME OFF ? * possiamo osservare che esaminando il responso della richiesta permessi vengono attivati / disattivati pulsanti e posizioni utente sulla mappa.
Questo fa capire che certe funzionalita, soggette a restrizioni di permessi, sarebbe opportuno che partissero SOLO in questo metodo (onRequestPermissionsResult() ). Per il semplice motivo che se vado a richiedere permessi che sono già stati concessi, in questo metodo il sistema operativo mi passerà comunque la risposta, ed in base a questa potrò muovermi.

Quindi, ricapitolando, ecco alcuni punti che potrebbero chiarirvi dei dubbi:

  1. Leggetevi la Documentazione ufficiale. Questa, per quanto prolissa (e forse anche un tantino confusa), può nella maggior parte dei casi risolvere il problema che vi sta assillando. Soprattutto date un’occhiata ai Livellli di protezione, in modo da capire se e quando richiedere o meno il coinvolgimento dell’utente della vostra fantastica App, in modo che il funzionamento sia garantito.
  2. Una volta capito come dovrebbero funzionare, cercate di assimilare un concetto di base. Di per sé la richiesta di un’autorizzazione è un’operazione parecchio invasiva, soprattutto perché, ad oggi, moltissimi utenti sono diffidenti nel dare autorizzazioni alle App perché si sentono “controllati”. Quindi si deve cercare di pensare al flusso dell’App in modo che guidi il più possibile a questa operazione avendo già coinvolto l’utente. Vi faccio un esempio: se la vostra App prevede l’utilizzo del salvataggio di documenti nella memoria del telefono, è necessario che l’utente sia coinvolto nel flusso della richiesta dei permessi *SE E SOLO SE* sta tentando di effettuare questa operazione di salvataggio. Ovvero, a meno che la funzionalità principale dell’App non sia proprio il salvataggio di documenti, sarebbe opportuno chiedere i permessi all’utente solo quando questo sta salvando un documento ed i permessi non sono stati accordati. Perché dico questo? Poniamo il caso che un’App che sto progettando abbia bisogno di 3 tipi di permessi espliciti: Fotocamera, Salvataggio files e Localizzazione GPS. Ora, se sono pigro (sbagliando), chiedo tutti i permessi subito, all’apertura dell’App, in modo da “togliermi subito il sassolino dalla scarpa”. Ovviamente non c’è niente di più sbagliato, oppure giusto per togliersi di mezzo subito una bella fetta di utilizzatori potenziali dell’App. Ci sono utenti a cui non da fastidio rispondere alla domanda “Vuoi concedere i permessi di localizzazione?” nonostante non ci sia neanche una mappa caricata nell’Activity attuale, ci sono invece utenti che non appena vedono le finestre di richiesta permessi si insospettiscono e chiudono / disinstallano l’App al volo.
  3. Prima di chiedere un’autorizzazione e mostrare il dialog di sistema per richiedere i permessi date sempre una spiegazione del perché e come andrete ad utilizzare quelle funzionalità. Ad esempio, se la vostra App ha una mappa in cui si vuole visualizzare il classico puntino blu della posizione dell’utente, è necessario richiedere i permessi di localizzazione. Per questo, la prima volta che si apre l’App, sarebbe bene spiegare, in un OnBoarding oppure in un dialog quando la mappa è caricata,  il perché andremo a chiedere i permessi. Un AlertDialog che dice “Se vuoi vedere la tua posizione mostrata sulla mappa è necessario che tu accetti la richiesta di concedere l’accesso ai permessi di localizzazione all’APP. Vuoi continuare?“. SOLO a questo punto e se l’utente accetta, mostreremo il dialog di sistema.

Alla prossima, gente!   PS: dimenticavo, se i permessi vengono richiesti in un Fragment piuttosto che in un’Activity, ricordatevi di implementare il metodo onRequestPermissionsResults([…]) e di richiamare il super.onRequestPermissionsResults() nell’Activity, altrimenti potrete attendere la chiamata al onRequestPermissionsResults([..]) del Fragment fino alla notte dei tempi a venire.

Andrea Fastame

Tags :