Per dare agli utenti un maggiore controllo sui propri file e limitare il disordine, Android 10 ha introdotto un nuovo paradigma di archiviazione per le app chiamato archiviazione mirata. L'archiviazione mirata cambia il modo in cui le app archiviano e accedono ai file sull'unità di archiviazione esterna di un dispositivo. Per aiutarti a eseguire la migrazione della tua app in modo che supporti l'archiviazione mirata, segui le best practice per i casi d'uso comuni dell'archiviazione descritti in questa guida. I casi d'uso sono organizzati in due categorie: gestione dei file multimediali e gestione dei file non multimediali.
In molti casi, la tua app crea file a cui altre app non devono o non dovrebbero accedere. Il sistema fornisce posizioni di archiviazione specifiche per le app per gestire questi file.
Per scoprire di più su come archiviare e accedere ai file su Android, consulta le guide di formazione sull'archiviazione.
Gestire i file multimediali
In questa sezione vengono descritti alcuni dei casi d'uso comuni per la gestione dei file multimediali (file video, immagine e audio) e viene illustrato l'approccio di alto livello che la tua app può utilizzare. La tabella seguente riassume ciascuno di questi casi d'uso e fornisce link alle sezioni che contengono ulteriori dettagli.
| Caso d'uso | Riepilogo |
|---|---|
| Mostrare tutti i file immagine o video | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Mostrare immagini o video da una cartella specifica | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Accedere alle informazioni sulla posizione dalle foto | Utilizza un approccio se la tua app utilizza l'archiviazione mirata. Utilizza un approccio diverso se la tua app disattiva l'archiviazione mirata. |
| Definire la posizione di archiviazione per i nuovi download | Utilizza un approccio se la tua app utilizza l'archiviazione mirata. Utilizza un approccio diverso se la tua app disattiva l'archiviazione mirata. |
| Esportare i file multimediali dell'utente su un dispositivo | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Modificare o eliminare più file multimediali in un'unica operazione | Utilizza un approccio per Android 11. Per Android 10, disattiva l'archiviazione mirata e utilizza l'approccio per Android 9 e versioni precedenti. |
| Importare una singola immagine già esistente | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Acquisire una singola immagine | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Condividere file multimediali con altre app | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Condividere file multimediali con un'app specifica | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Accedere ai file da codice o librerie che utilizzano percorsi di file diretti | Utilizza un approccio per Android 11. Per Android 10, disattiva l'archiviazione mirata e utilizza l'approccio per Android 9 e versioni precedenti. |
Mostrare file immagine o video da più cartelle
Esegui una query su una raccolta multimediale
utilizzando l'API query(). Per filtrare o ordinare i file multimediali, modifica i parametri projection, selection,
selectionArgs, e sortOrder.
Mostrare immagini o video da una cartella specifica
Utilizza questo approccio:
- Segui le best practice descritte in Richiedere le autorizzazioni delle app,
richiedi l'autorizzazione
READ_EXTERNAL_STORAGE. - Recupera i file multimediali in base al valore di
MediaColumns.DATA, che contiene il percorso assoluto del file system dell'elemento multimediale sul disco.
Nota: quando accedi a un file multimediale esistente, puoi utilizzare il valore
della colonna DATA
nella tua logica. Questo perché questo valore ha un percorso di file valido.
Tuttavia, non dare per scontato che il file sia sempre disponibile. Preparati a gestire
eventuali errori di I/O basati su file che potrebbero verificarsi.
Per creare o aggiornare un file multimediale, invece, non utilizzare la
DATA colonna. Utilizza invece le colonne DISPLAY_NAME e
RELATIVE_PATH.
Accedere alle informazioni sulla posizione dalle foto
Se la tua app utilizza l'archiviazione mirata, segui i passaggi descritti nella sezione Informazioni sulla posizione nelle fotografie della guida all'archiviazione multimediale.
Definire la posizione di archiviazione per i nuovi download
Se la tua app utilizza l'archiviazione mirata, presta attenzione alla posizione in cui scegli di archiviare i file multimediali che scarichi.
Se altre app richiedono l'accesso ai file, valuta la possibilità di utilizzare raccolte multimediali o raccolte di documenti ben definite per i download.
Su Android 11 e versioni successive, i file all'interno della directory esterna specifica dell'app
non sono accessibili ad altre app, anche se utilizzi DownloadManager per
recuperare questi file.
Esportare i file multimediali dell'utente su un dispositivo
Definisci una posizione predefinita appropriata per archiviare i file multimediali dell'utente:
- Consenti agli utenti di scegliere se rendere i propri file multimediali leggibili da altre app o meno, utilizzando lo spazio di archiviazione specifico dell'app o lo spazio di archiviazione condiviso.
- Consenti agli utenti di esportare i file dalle directory specifiche dell'app in una posizione più accessibile in generale. Utilizza le raccolte di immagini, video e audio di MediaStore per esportare i file multimediali nella galleria del dispositivo.
Modificare o eliminare più file multimediali in un'unica operazione
Incorpora la logica in base alle versioni di Android su cui viene eseguita la tua app.
Esecuzione su Android 11
Utilizza questo approccio:
- Crea un intent in attesa per la richiesta di scrittura o eliminazione dell'app utilizzando
MediaStore.createWriteRequest()oMediaStore.createTrashRequest()e poi chiedi all'utente l'autorizzazione per modificare un insieme di file richiamando l'intent. Valuta la risposta dell'utente:
- Se l'autorizzazione è stata concessa, procedi con l'operazione di modifica o eliminazione.
- Se l'autorizzazione non è stata concessa, spiega all'utente perché la funzionalità della tua app richiede l'autorizzazione.
Scopri di più su come gestire i gruppi di file multimediali utilizzando questi metodi disponibili su Android 11 e versioni successive.
Esecuzione su Android 10
Se la tua app ha come target Android 10 (livello API 29), disattiva l'archiviazione mirata e continua a utilizzare l'approccio per Android 9 e versioni precedenti per eseguire questa operazione.
Esecuzione su Android 9 o versioni precedenti
Utilizza questo approccio:
- Segui le best practice descritte in Richiedere le autorizzazioni delle app,
richiedi l'autorizzazione
WRITE_EXTERNAL_STORAGE. - Utilizza l'API
MediaStoreper modificare o eliminare i file multimediali.
Importare una singola immagine già esistente
Quando vuoi importare una singola immagine già esistente (ad esempio, da utilizzare come foto per il profilo di un utente), la tua app può utilizzare la propria UI per l'operazione oppure il picker di sistema.
Presentare la propria interfaccia utente
Utilizza questo approccio:
- Segui le best practice descritte in Richiedere le autorizzazioni delle app,
richiedi l'autorizzazione
READ_EXTERNAL_STORAGE. - Utilizza l'
query()API per eseguire una query su una raccolta multimediale. - Mostra i risultati nell'interfaccia utente personalizzata della tua app.
Utilizzare il picker di sistema
Utilizza l'ACTION_GET_CONTENT
intent, che chiede all'utente di scegliere un'immagine da importare.
Se vuoi filtrare i tipi di immagini che il picker di sistema presenta all'
utente tra cui scegliere, puoi utilizzare
setType()
o EXTRA_MIME_TYPES.
Acquisire una singola immagine
Quando vuoi acquisire una singola immagine da utilizzare nella tua app (ad esempio, da utilizzare
come foto per il profilo di un utente), utilizza l'
ACTION_IMAGE_CAPTURE
intent per chiedere all'utente di scattare una foto utilizzando la fotocamera del dispositivo. Il sistema
archivia la foto acquisita nella
MediaStore.Images tabella.
Condividere file multimediali con altre app
Utilizza il
insert()
metodo per aggiungere record direttamente in MediaStore. Per saperne di più, consulta la sezione Aggiungere un elemento della guida all'archiviazione multimediale.
Condividere file multimediali con un'app specifica
Utilizza il componente FileProvider di Android, come descritto nella guida Configurare la condivisione
di file.
Accedere ai file da codice o librerie che utilizzano percorsi di file diretti
Incorpora la logica in base alle versioni di Android su cui viene eseguita la tua app.
Esecuzione su Android 11
Utilizza questo approccio:
- Segui le best practice descritte in Richiedere le autorizzazioni delle app,
richiedi l'autorizzazione
READ_EXTERNAL_STORAGE. - Accedi ai file utilizzando percorsi di file diretti.
Per saperne di più, consulta la sezione su come aprire i file multimediali utilizzando percorsi di file diretti.
Esecuzione su Android 10
Se la tua app ha come target Android 10 (livello API 29), disattiva l'archiviazione mirata e continua a utilizzare l'approccio per Android 9 e versioni precedenti per eseguire questa operazione.
Esecuzione su Android 9 o versioni precedenti
Utilizza questo approccio:
- Segui le best practice descritte in Richiedere le autorizzazioni delle app,
richiedi l'autorizzazione
WRITE_EXTERNAL_STORAGE. - Accedi ai file utilizzando percorsi di file diretti.
Gestire i file non multimediali
In questa sezione vengono descritti alcuni dei casi d'uso comuni per la gestione dei file non multimediali e viene illustrato l'approccio di alto livello che la tua app può utilizzare. La tabella seguente riassume ciascuno di questi casi d'uso e fornisce link alle sezioni che contengono ulteriori dettagli.
| Caso d'uso | Riepilogo |
|---|---|
| Aprire un file documento | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Scrivere su file su volumi di archiviazione secondari | Utilizza un approccio per Android 11. Utilizza un approccio diverso per le versioni precedenti versions di Android. |
| Eseguire la migrazione dei file esistenti da una posizione di archiviazione legacy | Esegui la migrazione dei file all'archiviazione mirata, se possibile. Disattiva l'archiviazione mirata per Android 10, se necessario. |
| Condividere contenuti con altre app | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Memorizzare nella cache i file non multimediali | Utilizza lo stesso approccio per tutte le versioni di Android. |
| Esportare i file non multimediali su un dispositivo | Utilizza un approccio se la tua app utilizza l'archiviazione mirata. Utilizza un approccio diverso se la tua app disattiva l'archiviazione mirata. |
Aprire un file documento
Utilizza l'ACTION_OPEN_DOCUMENT intent per chiedere all'utente di scegliere un file da aprire utilizzando il picker di sistema. Se vuoi filtrare i tipi di file che il picker di sistema presenterà all' utente tra cui scegliere, puoi utilizzare setType() o EXTRA_MIME_TYPES.
Ad esempio, puoi trovare tutti i file PDF, ODT e TXT utilizzando il seguente codice:
Kotlin
startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" putExtra(Intent.EXTRA_MIME_TYPES, arrayOf( "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt )) }, REQUEST_CODE )
Java
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt }); startActivityForResult(intent, REQUEST_CODE);
Scrivere su file su volumi di archiviazione secondari
I volumi di archiviazione secondari includono le schede SD. Puoi accedere alle informazioni su un determinato volume di archiviazione utilizzando la
StorageVolume classe.
Incorpora la logica in base alla versione di Android su cui viene eseguita la tua app.
Esecuzione su Android 11
Utilizza questo approccio:
- Utilizza il modello di archiviazione mirata.
- Imposta come target Android 10 (livello API 29) o versioni precedenti.
- Dichiara l'
WRITE_EXTERNAL_STORAGEautorizzazione. - Esegui uno dei seguenti tipi di accesso:
- Accesso ai file utilizzando l'API
MediaStore. - Accesso diretto al percorso del file utilizzando API come
Fileofopen().
- Accesso ai file utilizzando l'API
Esecuzione su versioni precedenti
Utilizza il Storage Access Framework, che consente agli utenti di selezionare la posizione su un volume di archiviazione secondario in cui la tua app può scrivere il file.
Eseguire la migrazione dei file esistenti da una posizione di archiviazione legacy
Una directory è considerata una posizione di archiviazione legacy se non è una directory specifica dell'app o una directory condivisa pubblica. Se la tua app crea o utilizza file in una posizione di archiviazione legacy, ti consigliamo di eseguire la migrazione dei file dell'app in posizioni accessibili con l'archiviazione mirata e di apportare le modifiche necessarie all'app per lavorare con i file nell'archiviazione mirata.
Mantenere l'accesso alla posizione di archiviazione legacy per la migrazione dei dati
La tua app deve mantenere l'accesso alla posizione di archiviazione legacy per eseguire la migrazione di tutti i file dell'app in posizioni accessibili con l'archiviazione mirata. L'approccio da utilizzare dipende dal livello API target della tua app.
Se la tua app ha come target Android 11
Imposta il
preserveLegacyExternalStorageflag sutrueper mantenere il modello di archiviazione legacy in modo che la tua app possa eseguire la migrazione dei dati di un utente quando esegue l'upgrade alla nuova versione dell' app che ha come target Android 11.Continua a disattivare l'archiviazione mirata in modo che la tua app possa continuare ad accedere ai file nella posizione di archiviazione legacy sui dispositivi Android 10.
Se la tua app ha come target Android 10
Disattiva l'archiviazione mirata per semplificare la manutenzione del comportamento della tua app nelle versioni di Android.
Eseguire la migrazione dei dati dell'app
Quando la tua app è pronta per la migrazione, utilizza il seguente approccio:
- Imposta come target Android 10 o versioni precedenti.
- Disattiva l'archiviazione mirata in modo che la tua app abbia accesso ai file di cui devi eseguire la migrazione.
-
Esegui il deployment del codice che utilizza l'API
Fileper spostare i file dalla loro posizione attuale in/sdcard/a una posizione accessibile con l'archiviazione mirata:- Sposta tutti i file privati dell'app nella directory restituita dal
getExternalFilesDir()metodo. - Sposta tutti i file non multimediali condivisi in una sottodirectory dedicata all'app della directory
Downloads/.
- Sposta tutti i file privati dell'app nella directory restituita dal
- Rimuovi le directory di archiviazione legacy della tua app dalla
/sdcard/directory.
Dopo che gli utenti hanno installato la nuova versione della tua app, completano la procedura di migrazione dei dati sui propri dispositivi. Puoi monitorare la procedura di migrazione nella tua base utenti creando un evento di analisi.
Dopo che gli utenti hanno eseguito la migrazione dei dati, pubblica un altro aggiornamento della tua app, in cui hai come target Android 11.
Condividere contenuti con altre app
Per condividere i file della tua app con un'altra app, utilizza un
FileProvider. Per le app che devono condividere
file tra loro, ti consigliamo di utilizzare un content
provider per ogni app e
poi di sincronizzare i dati man mano che le app vengono aggiunte alla raccolta.
Memorizzare nella cache i file non multimediali
L'approccio da utilizzare dipende dal tipo di file che devi memorizzare nella cache.
- File di piccole dimensioni o file che contengono informazioni sensibili: utilizza
Context#getCacheDir(). - File di grandi dimensioni o file che non contengono informazioni sensibili: utilizza
Context#getExternalCacheDir().
Esportare i file non multimediali su un dispositivo
Definisci una posizione predefinita appropriata per archiviare i file non multimediali. Consenti agli utenti di esportare i file dalle directory specifiche dell'app in una posizione più accessibile in generale. Utilizza i download o le raccolte di documenti di MediaStore per esportare i file non multimediali su l dispositivo.
Gestire i file specifici dell'app
Nel caso in cui la tua app crei file a cui altre app non devono o non dovrebbero accedere, puoi archiviare questi file in posizioni di archiviazione specifiche dell'app.
Directory di memoria interna
Il sistema impedisce ad altre app di accedere a queste posizioni e, su Android 10 (livello API 29) e versioni successive, queste posizioni sono criptate. Queste posizioni sono un buon posto per archiviare dati sensibili a cui solo la tua app può accedere.
Directory di archiviazione esterna
Se la memoria interna non fornisce spazio sufficiente per archiviare i file specifici dell'app, valuta la possibilità di utilizzare l'archiviazione esterna. Sebbene sia possibile che un'altra app acceda a queste directory se dispone delle autorizzazioni appropriate, i file archiviati in queste directory sono destinati all'uso esclusivo della tua app.
Su Android 4.4 (livello API 19) o versioni successive, la tua app non deve richiedere autorizzazioni relative all'archiviazione per accedere alle directory specifiche dell'app all'interno dell'archiviazione esterna.
Quando l'utente disinstalla la tua app, i file salvati nell'archiviazione specifica dell'app vengono rimossi, pertanto non devi utilizzare questa archiviazione per salvare elementi che l'utente si aspetta che persistano indipendentemente dalla tua app.
Disattivare temporaneamente l'archiviazione mirata
Prima che la tua app sia completamente compatibile con l'archiviazione mirata, puoi disattivarla temporaneamente, sia in test sia nell'app di produzione.
Disattivare nei test
Su Android 10 (livello API 29) e versioni successive, i test della tua app vengono eseguiti in una sandbox di archiviazione per impostazione predefinita. Questa sandbox impedisce alla tua app di accedere ai file al di fuori della directory specifica dell'app e delle directory condivise pubblicamente.
Se un test genera file per l'host, ad esempio screenshot, dati di debug, dati di copertura o metriche delle prestazioni, puoi scrivere questi file nelle directory globali. Per farlo, aggiungi il seguente flag all'harness pertinente che richiama am instrument:
-e no-isolated-storage 1
Questo flag influisce su tutto il comportamento del caso di test instrumentato e su tutto il codice di test richiamato. Pertanto, quando utilizzi questo flag, non puoi convalidare la compatibilità della tua app con l'archiviazione mirata. Per l'output dei test, è preferibile scrivere nell'archiviazione con ambito dell'app leggibile dalla shell. Dopodiché puoi estrarre la directory con ambito dell'app. Per determinare la directory da cui estrarre, chiama
getExternalMediaDirs().
Disattivare nell'app di produzione
Se la tua app ha come target Android 10 (livello API 29) o versioni precedenti, puoi disattivare temporaneamente l'archiviazione mirata nell'app di produzione. Se hai come target Android 10, devi impostare il valore di requestLegacyExternalStorage su true nel file manifest dell'app:
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
Per testare il comportamento di un'app che ha come target Android 10 o versioni precedenti quando utilizza l'archiviazione mirata, puoi attivare il comportamento impostando il valore di requestLegacyExternalStorage su false. Se stai eseguendo i test su un dispositivo con Android 11, puoi anche utilizzare i flag di compatibilità delle app per testare il comportamento della tua app con o senza archiviazione mirata.
Risorse aggiuntive
Per saperne di più sull'archiviazione di Android, consulta i seguenti materiali: