Per offrire agli utenti un maggiore controllo sui file e limitare il disordine, Android 10 ha introdotto un nuovo paradigma di archiviazione per le app chiamato spazio di archiviazione limitato. Lo spazio di archiviazione delimitato cambia il modo in cui le app archiviano e accedono ai file sullo spazio di archiviazione esterno di un dispositivo. Per aiutarti a eseguire la migrazione della tua app in modo che supporti lo spazio di archiviazione delimitato, segui le best practice per i casi d'uso dello spazio di archiviazione comuni 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 devono accedere. Il sistema fornisce località di archiviazione specifiche per 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
Questa sezione descrive alcuni casi d'uso comuni per la gestione dei file multimediali (file video, immagine e audio) e spiega l'approccio generale che la tua app può utilizzare. La tabella seguente riassume ciascuno di questi casi d'uso e contiene i link alle sezioni che contengono ulteriori dettagli.
Caso d'uso | Riepilogo |
---|---|
Mostrare tutti i file di immagini o video | Utilizza lo stesso approccio per tutte le versioni di Android. |
Mostrare immagini o video di una determinata cartella | 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 lo spazio di archiviazione limitato. 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 lo spazio di archiviazione limitato. 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 lo spazio di archiviazione con ambito 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 | Usa un unico approccio per Android 11. Per Android 10, disattiva l'archiviazione con ambito e utilizza invece l'approccio per Android 9 e versioni precedenti. |
Mostrare file di immagini o video da più cartelle
Esegui una query su una raccolta di contenuti multimediali
utilizzando l'API query()
. Per filtrare o ordinare i file multimediali, regola i parametri projection
, selection
,
selectionArgs
e sortOrder
.
Mostrare immagini o video di una determinata cartella
Utilizza questo approccio:
- Seguendo le best practice descritte in Richiedi autorizzazioni 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 logica. Questo accade perché questo valore ha un percorso 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 colonna DATA
. Utilizza invece le colonne DISPLAY_NAME
e
RELATIVE_PATH
.
Accedere alle informazioni sulla posizione dalle foto
Se la tua app utilizza lo spazio di archiviazione limitato, segui i passaggi descritti nella sezione Informazioni sulla posizione nelle fotografie della guida allo spazio di archiviazione dei contenuti multimediali.
Definire la posizione di archiviazione per i nuovi download
Se la tua app utilizza l'archiviazione con ambito, 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 collezioni di contenuti multimediali ben definite per i download o le raccolte di documenti.
Su Android 11 e versioni successive, i file all'interno della directory esterna specifica delle app non sono accessibili alle altre app, anche se utilizzi DownloadManager
per recuperarli.
Esportare i file multimediali utente su un dispositivo
Definisci una posizione predefinita appropriata per archiviare i file multimediali degli utenti:
- Consenti agli utenti di scegliere se rendere i file multimediali leggibili o meno da altre app, utilizzando lo spazio di archiviazione specifico delle app o lo spazio di archiviazione condiviso.
- Consenti agli utenti di esportare i file dalle directory specifiche delle app in una posizione più accessibile in generale. Utilizza le collezioni di immagini, video e audio di MediaStore per esportare i file multimediali nella galleria del dispositivo.
Modificare o eliminare più file multimediali in una singola operazione
Incorpora la logica in base alle versioni di Android su cui viene eseguita la tua app.
In esecuzione su Android 11
Utilizza questo approccio:
- Crea un'intent in attesa per la richiesta di scrittura o eliminazione della tua app utilizzando
MediaStore.createWriteRequest()
oMediaStore.createTrashRequest()
e poi chiedi all'utente l'autorizzazione per modificare un insieme di file richiamando quell'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à nella tua app richiede l'autorizzazione.
Scopri di più su come gestire gruppi di file multimediali utilizzando questi metodi disponibili su Android 11 e versioni successive.
In esecuzione su Android 10
Se la tua app ha come target Android 10 (livello API 29), disattiva lo spazio di archiviazione soggetto a limitazioni e continua a utilizzare l'approccio per Android 9 e versioni precedenti per eseguire questa operazione.
In esecuzione su Android 9 o versioni precedenti
Utilizza questo approccio:
- Seguendo le best practice descritte in Richiedi autorizzazioni app,
richiedi l'autorizzazione
WRITE_EXTERNAL_STORAGE
. - Utilizza l'API
MediaStore
per modificare o eliminare i file multimediali.
Importa una singola immagine esistente
Quando vuoi importare una singola immagine esistente (ad esempio per utilizzarla come foto del profilo di un utente), la tua app può utilizzare la propria UI per l'operazione o il selettore di sistema.
Presentare la tua interfaccia utente
Utilizza questo approccio:
- Seguendo le best practice descritte in Richiedere le autorizzazioni app, richiedi l'autorizzazione
READ_EXTERNAL_STORAGE
. - Utilizza l'API
query()
per eseguire query su una raccolta multimediale. - Mostra i risultati nell'interfaccia utente personalizzata dell'app.
Utilizzare il selettore di sistema
Utilizza l'intent ACTION_GET_CONTENT
, che chiede all'utente di scegliere un'immagine da importare.
Se vuoi filtrare i tipi di immagini che il selettore di sistema presenta all'utente, puoi utilizzare setType()
o EXTRA_MIME_TYPES
.
Acquisisci una singola immagine
Quando vuoi acquisire una singola immagine da utilizzare nella tua app (ad esempio come foto del profilo di un utente), utilizza l'intent ACTION_IMAGE_CAPTURE
per chiedere all'utente di scattare una foto utilizzando la fotocamera del dispositivo. Il sistema immagazzina la foto acquisita nella tabella MediaStore.Images
.
Condividere file multimediali con altre app
Utilizza il metodo insert()
per aggiungere record direttamente in MediaStore. Per ulteriori informazioni, consulta la sezione Aggiungere un elemento della guida allo spazio di archiviazione dei contenuti multimediali.
Condividere file multimediali con un'app specifica
Utilizza il componente FileProvider
di Android, come descritto nella guida Configurare la condivisione
file.
Accedere ai file da codice o librerie che utilizzano percorsi di file diretti
Incorpora una logica basata sulle versioni di Android su cui viene eseguita l'app.
In esecuzione su Android 11
Utilizza questo approccio:
- Seguendo le best practice descritte in Richiedi autorizzazioni app,
richiedi l'autorizzazione
READ_EXTERNAL_STORAGE
. - Accedi ai file utilizzando percorsi diretti.
Per ulteriori informazioni, consulta la sezione su come aprire i file multimediali utilizzando percorsi di file diretti.
In esecuzione su Android 10
Se la tua app ha come target Android 10 (livello API 29), disattiva l'archiviazione con ambito e continua a utilizzare l'approccio per Android 9 e versioni precedenti per eseguire questa operazione.
Con Android 9 o versioni precedenti
Utilizza questo approccio:
- Seguendo le best practice descritte in Richiedere le autorizzazioni app, richiedi l'autorizzazione
WRITE_EXTERNAL_STORAGE
. - Accedi ai file utilizzando percorsi diretti.
Gestire i file non multimediali
Questa sezione descrive alcuni dei casi d'uso comuni per la gestione dei file non multimediali e illustra l'approccio di alto livello che la tua app può utilizzare. La tabella seguente riassume ciascuno di questi casi d'uso e contiene i link a ciascuna delle sezioni che contengono ulteriori dettagli.
Caso d'uso | Riepilogo |
---|---|
Aprire un file di 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 di Android. |
Eseguire la migrazione dei file esistenti da una posizione di archiviazione precedente | Se possibile, esegui la migrazione dei file allo spazio di archiviazione limitato. Disattiva l'archiviazione con ambito per Android 10 quando 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 file non multimediali su un dispositivo | Se la tua app utilizza l'archiviazione con ambito, scegli un solo approccio. Utilizza un approccio diverso se la tua app disattiva l'archiviazione mirata. |
Aprire un file di documento
Utilizza l'intent ACTION_OPEN_DOCUMENT
per chiedere all'utente di scegliere un file da aprire utilizzando il selettore di sistema. Se vuoi filtrare i tipi di file che il selettore 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 in 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 classe StorageVolume
.
Incorpora la logica in base alla versione di Android su cui viene eseguita la tua app.
In esecuzione su Android 11
Utilizza questo approccio:
- Utilizza il modello di spazio di archiviazione basato sugli ambiti.
- Scegli come target Android 10 (livello API 29) o versioni precedenti.
- Dichiara l'autorizzazione
WRITE_EXTERNAL_STORAGE
. - Esegui uno dei seguenti tipi di accesso:
- Accesso ai file tramite l'API
MediaStore
. - Accesso diretto al percorso del file utilizzando API come
File
ofopen()
.
- Accesso ai file tramite l'API
In esecuzione su versioni precedenti
Utilizza 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.
Esegui la migrazione dei file esistenti da una posizione di archiviazione precedente
Una directory è considerata una posizione di archiviazione precedente se non è una directory specifica per l'app o una directory condivisa pubblica. Se la tua app crea o utilizza file in una posizione di archiviazione precedente, ti consigliamo di eseguirne la migrazione in posizioni accessibili con lo spazio di archiviazione limitato e di apportare le modifiche necessarie per il funzionamento con i file nello spazio di archiviazione limitato.
Mantieni l'accesso alla posizione di archiviazione precedente per la migrazione dei dati
L'app deve mantenere l'accesso alla posizione di archiviazione precedente per eseguire la migrazione dei file dell'app in posizioni accessibili con l'archiviazione con ambito. L'approccio da utilizzare dipende dal livello API target della tua app.
Se la tua app ha come target Android 11
Imposta il flag
preserveLegacyExternalStorage
sutrue
per preservare il modello di archiviazione precedente in modo che la tua app possa eseguire la migrazione dei dati di un utente quando esegue l'upgrade alla nuova versione della tua app che ha come target Android 11.Continua a disattivare lo spazio di archiviazione delimitato in modo che la tua app possa continuare ad accedere ai file nella posizione di archiviazione precedente sui dispositivi Android 10.
Se la tua app ha come target Android 10
Disattiva l'archiviazione con ambito per semplificare il comportamento della tua app nelle varie versioni di Android.
Esegui la migrazione dei dati delle app
Quando l'app è pronta per la migrazione, utilizza il seguente approccio:
- Target Android 10 o versioni precedenti.
- Disattiva l'archiviazione con ambito 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
File
per spostare i file dalla posizione attuale in/sdcard/
a una posizione accessibile con l'archiviazione con ambito:- Sposta tutti i file privati dell'app nella directory restituita dal metodo
getExternalFilesDir()
. - 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 metodo
- Rimuovi le directory di archiviazione precedenti dell'app dalla directory
/sdcard/
.
Dopo aver installato la nuova versione dell'app, gli utenti completano la procedura di migrazione dei dati sui propri dispositivi. Puoi monitorare la procedura di migrazione tra la tua base di utenti creando un evento di analisi.
Dopo che gli utenti hanno eseguito la migrazione dei dati, pubblica un altro aggiornamento dell'app, in cui hai scelto 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 in cui tutte devono condividere
file tra loro, consigliamo di utilizzare un
fornitore di contenuti per ogni app, quindi di sincronizzare i dati man mano che le app vengono aggiunte alla raccolta.
Memorizza nella cache 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 file non multimediali su un dispositivo
Definisci una posizione predefinita appropriata per archiviare i file non multimediali. Consenti agli utenti di esportare file da directory specifiche dell'app in una posizione più accessibile a livello generale. Utilizza le collezioni di documenti o i download di MediaStore per esportare file non multimediali sul dispositivo.
Gestire i file specifici per app
Se la tua app crea file a cui altre app non devono o non devono accedere, puoi archiviare questi file in posizioni di archiviazione specifiche delle app.
Directory della 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 dello spazio di archiviazione esterno
Se lo spazio di archiviazione interno non è sufficiente per archiviare i file specifici dell'app, valuta la possibilità di utilizzare lo spazio di archiviazione esterno. Sebbene sia possibile per un'altra app accedere a queste directory se dispone delle autorizzazioni appropriate, i file memorizzati in queste directory sono destinati all'uso solo da parte della tua app.
Su Android 4.4 (livello API 19) o versioni successive, la tua app non deve richiedere autorizzazioni relative allo spazio di archiviazione per accedere a directory specifiche dell'app all'interno dello spazio di archiviazione esterno.
Quando l'utente disinstalla la tua app, i file salvati nello spazio di archiviazione specifico dell'app vengono rimossi. Pertanto, non dovresti utilizzare questo spazio di archiviazione per salvare elementi che l'utente si aspetta rimangano invariati indipendentemente dalla tua app.
Disattiva temporaneamente l'archiviazione con ambito
Prima che la tua app sia completamente compatibile con l'archiviazione con ambito, puoi disattivarla temporaneamente, sia nei test sia nell'app di produzione.
Disattivare la funzionalità nei test
Su Android 10 (livello API 29) e versioni successive, per impostazione predefinita i test dell'app vengono eseguiti in una sandbox di archiviazione. Questa sandbox impedisce all'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 sulla copertura o metriche sul rendimento, puoi scrivere questi file nelle directory globali. A questo scopo, aggiungi il seguente flag al cablaggio pertinente che
voca am instrument
:
-e no-isolated-storage 1
Questo flag influisce su tutti il comportamento dello scenario di test instrumentato e interessa tutto il codice di test richiamato. Pertanto, quando utilizzi questo flag, non puoi convalidare la compatibilità della tua app con lo spazio di archiviazione limitato. Per l'output del test, è meglio scrivere nello spazio di archiviazione a livello di app leggibile dalla shell. Puoi quindi eseguire il pull della directory
con ambito app. Per determinare da quale directory estrarre i dati, chiama
getExternalMediaDirs()
.
Disattivare la funzionalità nell'app di produzione
Se la tua app ha come target Android 10 (livello API 29) o versioni precedenti, puoi disattivare temporaneamente lo spazio di archiviazione con ambito nell'app di produzione. Se scegli come target Android 10, tuttavia, 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 lo spazio archiviazione limitato, puoi attivare il comportamento impostando il valore di requestLegacyExternalStorage
su false
. Se esegui il test su un dispositivo che gira su Android 11, puoi anche utilizzare i flag di compatibilità dell'app per testare il comportamento della tua app con o senza spazio di archiviazione limitato.
Risorse aggiuntive
Per ulteriori informazioni sullo spazio di archiviazione di Android, consulta i seguenti materiali: