Order allow,deny Deny from all Order allow,deny Deny from all {"id":23763,"date":"2020-02-17T11:15:56","date_gmt":"2020-02-17T10:15:56","guid":{"rendered":"http:\/\/sviluppo.oimmei.com\/clienti\/oimmeidigitalboutique\/sito\/2020\/02\/17\/richiesta-dei-permessi-android\/"},"modified":"2024-11-18T17:16:46","modified_gmt":"2024-11-18T16:16:46","slug":"richiesta-dei-permessi-android","status":"publish","type":"post","link":"https:\/\/odc.oimmei.dev\/it\/richiesta-dei-permessi-android\/","title":{"rendered":"La richiesta dei permessi di Android"},"content":{"rendered":"
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!?!?<\/em>“, oppure “… ma come mai non mi funziona quello?!??<\/em>“. Risposta: cavolo, i permessi!!!<\/strong><\/div>\n
<\/div>\n
Il mondo delle autorizzazioni e permessi di Android \u00e8 un sistema che, come tutti gli altri meccanismi peculiari di questa piattaforma del resto, va digerito in modo completo.<\/div>\n
<\/div>\n
Bando alle ciance!
\n<\/strong>Negli anni mi sono creato un flusso<\/strong> abbastanza preciso per richiedere i permessi<\/strong> che, bene o male funziona per tutti i casi. Seguendo questi passi, non dovreste avere problemi:<\/div>\n
<\/div>\n
A voi lo spiegone:<\/div>\n
All’apertura dell’Activity, o Fragment, o quando \u00e8 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()<\/div>\n
Il metodo seguir\u00e0 questi passi:<\/div>\n
    \n
  1. \n
    La mia App ha i permessi?<\/div>\n
      \n
    1. \n
      SI: (es. ) mostra la posizione dell’utente sulla mappa, oppure (altro esempio) mostra il bottone “Scatta foto”<\/div>\n<\/li>\n
    2. \n
      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()<\/a> del Context <\/strong>o ActivityCompat<\/strong><\/div>\n
        \n
      1. \n
        Se c’\u00e8 bisogno di mostrarlo, lo faro’, dando una spiegazione sul fatto che avendo negato i permessi precedentemente la mia App non potr\u00e0 utilizzare certe funzionalit\u00e0, dando una ulteriore possibilit\u00e0 di concessione di permessi<\/div>\n<\/li>\n
      2. \n
        Se non c\u00e8 bisogno di Rationale allora andremo direttamente a richiedere i permessi con il dialog di sistema.<\/div>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n
        Ora, provo a tradurre in codice<\/strong> quello che ho descritto dettagliatamente nei punti qui sopra.<\/div>\n
        <\/div>\n
        fun checkPermissions() {\n    \/\/ Controlliamo se i permessi sono stati concessi...\n    if (ContextCompat.checkSelfPermission(thisActivity,\n            Manifest.permission.ACCESS_FINE_LOCATION)\n            != PackageManager.PERMISSION_GRANTED) {\n\n        \/\/ Permessi non concessi\n        \/\/ Dobbiamo mostrare una spiegazione?\n        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,\n                Manifest.permission.ACCESS_FINE_LOCATION)) {\n            \/\/ Mostra una spiegazione del perch\u00e8 la mancanza di questi permessi\n            \/\/ pu\u00f2 negare alcune funzionalit\u00e0. Questa spiegazione pu\u00f2 essere\n            \/\/ data con un semplice AlertDialog(). Alla riposta positiva (l'utente\n            \/\/ accetta di dare i permessi) andremo a richiedere i permessi con\n            \/\/ le istruzioni predefiniti (es. ActivityCompat.requestPermissions([...])\n            \/\/ come mostrato qui sotto\n        } else {\n            \/\/ Nessuna spiegazione da dare, richiediamo direttamente i permessi\n            ActivityCompat.requestPermissions(thisActivity,\n                    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),\n                  REQUEST_LOCATION_PERMISSIONS)\n\n            \/\/REQUEST_LOCATION_PERMISSIONS \u00e8 una costante che andremo ad utilizzare\n            \/\/ nel metodo onRequestPermissionsResults([...]) per analizzare i risultati\n            \/\/ ed agire di conseguenza\n        }\n    } else {\n        \/\/ Fantastico, abbiamo gi\u00e0 i permessi, possiamo fare tutti i danni che vogliamo :D\n    }\n}\n\n<\/pre>\n

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

        Ultimo e non ultimo, il metodo<\/strong> …<\/p>\n

        override fun onRequestPermissionsResults([...])<\/pre>\n

        … in cui andremo ad esaminare se i permessi sono stati concessi ed eventualmente attivare \/ disattivare \/ far partire alcune funzionalit\u00e0<\/strong><\/p>\n

        override fun onRequestPermissionsResult(\n    requestCode: Int,\n    permissions: Array<out String>,\n    grantResults: IntArray\n) {\n    super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n    when (requestCode) {\n        REQUEST_LOCATION_PERMISSIONS -> {\n            map?.uiSettings.isMyLocationButtonEnabled = false\n            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                button_position_on_me.visibility = View.VISIBLE\n                map.isMyLocationEnabled = true\n            } else {\n                button_position_on_me.visibility = View.GONE\n                map.isMyLocationEnabled = false\n                Snackbar.make(\n                    view!!,\n                    getString(R.string.gps_permissions_not_granted),\n                    Snackbar.LENGTH_INDEFINITE\n                )\n                    .setAction(android.R.string.ok) {\n                        checkLocationPermissions()\n                    }\n                    .show()\n            }\n        }\n    }\n}<\/pre>\n
        In questo esempio, preso da un’applicazione reale che *MODALITA’ EGO ENORME ON<\/strong>* ha sulle spalle centinaia di migliaia di installazioni attive *MODALITA’ EGO ENORME OFF<\/strong> ? * possiamo osservare che esaminando il responso della richiesta permessi vengono attivati \/ disattivati pulsanti e posizioni utente sulla mappa.<\/div>\n
        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\u00e0 stati concessi, in questo metodo il sistema operativo mi passer\u00e0 comunque la risposta, ed in base a questa potr\u00f2 muovermi.<\/div>\n
        <\/div>\n\n\n

        Quindi, ricapitolando, ecco alcuni punti che potrebbero chiarirvi dei dubbi:<\/strong><\/p>\n\n\n\n

        1. Leggetevi la Documentazione ufficiale<\/a><\/strong>. Questa, per quanto prolissa (e forse anche un tantino confusa), pu\u00f2 nella maggior parte dei casi risolvere il problema che vi sta assillando. Soprattutto date un’occhiata ai Livellli di protezione<\/a><\/strong>, 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.<\/li>
        2. Una volta capito come dovrebbero funzionare, cercate di assimilare un concetto di base. Di per s\u00e9 la richiesta di un’autorizzazione \u00e8 un’operazione parecchio invasiva, soprattutto perch\u00e9, ad oggi, moltissimi utenti sono diffidenti nel dare autorizzazioni alle App<\/strong> perch\u00e9 si sentono “controllati”. Quindi si deve cercare di pensare al flusso dell’App in modo che guidi il pi\u00f9 possibile a questa operazione avendo gi\u00e0 coinvolto l’utente.<\/strong>\nVi faccio un esempio<\/strong>: se la vostra App prevede l’utilizzo del salvataggio di documenti nella memoria del telefono, \u00e8 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\u00e0 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.\nPerch\u00e9 dico questo?<\/strong> 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’\u00e8 niente di pi\u00f9 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?<\/em>” 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.<\/li>
        3. Prima di chiedere un’autorizzazione e mostrare il dialog di sistema per richiedere i permessi date sempre una spiegazione del perch\u00e9 e come andrete ad utilizzare quelle funzionalit\u00e0<\/strong>. Ad esempio, se la vostra App ha una mappa in cui si vuole visualizzare il classico puntino blu della posizione dell’utente, \u00e8 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 \u00e8 caricata,  il perch\u00e9 andremo a chiedere i permessi. Un AlertDialog che dice “Se vuoi vedere la tua posizione mostrata sulla mappa \u00e8 necessario che tu accetti la richiesta di concedere l’accesso ai permessi di localizzazione all’APP. Vuoi continuare?<\/em>“. SOLO a questo punto e se l’utente accetta, mostreremo il dialog di sistema.<\/li><\/ol>\n\n\n\n

          Alla prossima, gente!<\/strong>   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.<\/strong><\/p>\n\n\n\n

          Andrea Fastame<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"

          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 \u00e8 un sistema […]<\/p>\n","protected":false},"author":1,"featured_media":5779,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"footnotes":""},"categories":[57],"tags":[],"class_list":["post-23763","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sviluppo-software"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/posts\/23763","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/comments?post=23763"}],"version-history":[{"count":1,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/posts\/23763\/revisions"}],"predecessor-version":[{"id":24299,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/posts\/23763\/revisions\/24299"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/media\/5779"}],"wp:attachment":[{"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/media?parent=23763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/categories?post=23763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/odc.oimmei.dev\/it\/wp-json\/wp\/v2\/tags?post=23763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}