Introduzione
Le applicazioni Flutter sviluppate prima di Android 13 utilizzavano i permessi di accesso al file system in modo relativamente semplice. Tuttavia, con l'introduzione di Android 13 (API level 33), Google ha modificato il sistema dei permessi, rendendo necessaria una nuova configurazione per garantire il corretto funzionamento dei download e della gestione dei file. Questa relazione analizza il problema incontrato in un'app Flutter sviluppata nel 2022 e come è stato risolto con l'aggiornamento dei permessi richiesti.
Contesto
L'applicazione, sviluppata con la seguente configurazione dei permessi nel file AndroidManifest.xml
:.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
e con il relativo metodo dart per la richiesta del permesso di scrittura:
Future<bool> _requestWritePermission() async {
await Permission.storage.request();
return await Permission.storage.isGranted;
}
funziona correttamente fino ad Android 12. Per qualunque dispositivo Android 12 , che sia smartphone o tablet, il codice di base per ottenere i permessi di scrittura è quello sopra descritto.
Il Problema
Con l’uscita del sistema operativo Android 13 Tiramisù e versioni successive (da qui Android13+), l’app non segnala anomalie evidenti e continua a funzionare correttamente, ma il download non viene avviato, senza alcun avviso per l’utente. Inoltre, l'app non richiede più all’utente (contrariamente al suo funzionamento su OS precedenti) neppure le autorizzazioni alla scrittura sul file system. Un aggiornamento quindi del sistema operativo del dispositivo può creare un effetto collaterale che però non è evidenziato da alcun messaggio che possa ricondurre il problema all’aggiornamento del sistema.
Per molti utenti la cosa può essere trasparente, e il fatto che i download non si avviino può sembrare un problema del telefono stesso, e non dell’app.
La frase «L’ultimo aggiornamento del sistema operativo mi ha rovinato il telefono» è fin troppo comune, ma spesso si tratta solo di configurazioni deprecate o obsolete. L'unico indizio che ha portato allo scoprire un possibile problema è stato proprio l’assenza di alcun messaggio di richiesta di accesso allo storage del device. Eseguendo il codice dart in debug, la risposta del metodo _requestWritePermission()
è il valore false
. Il sistema nega l’accesso allo storage senza neanche richiederlo all’utente.
Modifica del Sistema di Permessi in Android 13+
A partire da Android 13, i permessi di accesso ai file multimediali sono stati suddivisi in specifiche categorie:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
Questi permessi sono richiesti per accedere a immagini, video e file audio, mentre il permesso generico READ_EXTERNAL_STORAGE
è stato deprecato e non è più supportato su Android13+.
La Soluzione Implementata
Per garantire la compatibilità con Android 13+, il codice per la gestione dei permessi è stato aggiornato come segue:
Future<bool> _requestStoragePermissions() async {
if (Platform.isAndroid && (await DeviceInfoPlugin().androidInfo).version.sdkInt >= 33) {
PermissionStatus images = await Permission.photos.request();
PermissionStatus videos = await Permission.videos.request();
PermissionStatus audio = await Permission.audio.request();
return images.isGranted || videos.isGranted || audio.isGranted;
} else {
PermissionStatus storage = await Permission.storage.request();
return storage.isGranted;
}
}
Questa funzione verifica la versione di Android e richiede i permessi corretti in base alla versione. La vecchia implementazione tramite Permission.storage.request
è valida comunque per i dispositivi iOS e le vecchie versioni di Android.
L'Alternativa (senza il rischio dei permessi)
Un aspetto interessante è che il download di un file non richiede necessariamente permessi speciali, a meno che non si voglia accedere direttamente al file system. Un'alternativa possibile è avviare il download senza richiedere permessi e aprire il file con un'applicazione appropriata:
void _downloadAndOpenFile(String url) async {
String? downloadDir=
(await DownloadsPath.downloadsDirectory())?.path;
await dio.download(url, "$downloadDir/$fileName")
.then((value) async {
if(value.statusCode == 200){
File file = await File('$downloadDir/$fileName');
OpenFile.open(
tempFile.path,
);
}
});
}
Questa soluzione evita la gestione esplicita dei permessi, poiché l'accesso al file scaricato è automatico. La soluzione proposta utilizza 3 plugin differenti, che non necessitano di permessi di accesso al filesystem, e sono:
- path_provider: plugin per l’accesso a directory e path comuni all’interno del filesystem. Utilizzato in questo caso per avere accesso alla directory “Downloads”.
- dio : plugin per effettuare richieste http. Utilizzato per scaricare il file tramite url fornita.
- open_file: plugin per aprire file su altre applicazioni tramite componente nativo. Utilizzato per visualizzare il file scaricato all’interno di un PDF viewer installato.
Conclusioni
L'aggiornamento delle policy sui permessi in Android 13 ha introdotto una gestione più granulare dell’accesso ai file. Per garantire la compatibilità con le nuove versioni di Android, è necessario aggiornare i permessi richiesti e gestire dinamicamente la richiesta in base alla versione del sistema operativo. In alternativa, è possibile avviare il download senza richiedere permessi, a condizione che l'app non necessiti di accedere direttamente a cartelle specifiche del file system.
Ti è piaciuto quanto hai letto? Iscriviti a MISPECIAL, la nostra newsletter, per ricevere altri interessanti contenuti.
Iscriviti a MISPECIAL