Casi d'uso e best practice per lo spazio di archiviazione di Android

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 eseguire la migrazione dell'app per supportare l'archiviazione con ambito, segui le best practice per i casi d'uso dello spazio di archiviazione descritti in questa guida. I casi d'uso sono organizzati in due categorie: gestione di file multimediali e gestione non multimediali.

In molti casi, la tua app crea file a cui altre app non devono o non devono accedere. Il sistema fornisce posizioni di archiviazione specifiche per le app. .

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 con 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 un determinato tipo cartella Utilizza lo stesso approccio per tutte le versioni di Android.
Accedi alle informazioni sulla posizione da 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 dei 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 in una singola operazione Utilizza un approccio per Android 11. Per Android 10, disattiva l'ambito spazio di archiviazione e usare invece l'approccio per Android 9 e versioni precedenti.
Importare un'immagine singola 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 lo spazio di archiviazione con ambito e utilizza 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 projection, selection, selectionArgs e sortOrder.

Mostra immagini o video da una determinata cartella

Utilizza questo approccio:

  1. Seguendo le best practice descritte in Richiedi autorizzazioni app, richiedi l'autorizzazione READ_EXTERNAL_STORAGE.
  2. Recupera i file multimediali in base al valore di MediaColumns.DATA, che contiene il percorso di file system assoluto per l'elemento multimediale su disco.

Nota: quando accedi a un file multimediale esistente, puoi utilizzare il valore di DATA nella tua logica. Questo perché questo valore ha un percorso file valido. Tuttavia, non dare per scontato che il file sia sempre disponibile. Preparati a gestirle eventuali errori di I/O basati su file.

Per creare o aggiornare un file multimediale, invece, non utilizzare la classe Colonna DATA. Usa invece i DISPLAY_NAME e RELATIVE_PATH colonne.

Accedere alle informazioni sulla posizione dalle foto

Se l'app utilizza l'archiviazione con ambito, segui i passaggi descritti in Informazioni sulla posizione nelle fotografie della guida all'archiviazione dei contenuti multimediali.

Definisci la posizione di archiviazione per i nuovi download

Se la tua app utilizza lo spazio archiviazione limitato, tieni presente la posizione in cui scegli di memorizzare i file multimediali scaricati.

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 per l'app non sono accessibili ad altre app, anche se utilizzi DownloadManager per recuperarli.

Esportare i file multimediali utente su un dispositivo

Definisci una posizione predefinita adeguata in cui archiviare i contenuti multimediali dell'utente file:

Modificare o eliminare più file multimediali in un'unica operazione

Incorpora una logica basata sulle versioni di Android su cui viene eseguita l'app.

In esecuzione su Android 11

Utilizza questo approccio:

  1. Crea un intent in attesa per la richiesta di scrittura o eliminazione della tua app utilizzando MediaStore.createWriteRequest() oppure MediaStore.createTrashRequest() e chiedi all'utente l'autorizzazione per modificare un insieme di file richiamando l'intento.
  2. 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 ne ha bisogno.

Scopri di più su come gestire gruppi di contenuti multimediali mediante questi file 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.

Con Android 9 o versioni precedenti

Utilizza questo approccio:

  1. Seguendo le best practice descritte in Richiedere le autorizzazioni app, richiedi WRITE_EXTERNAL_STORAGE autorizzazione.
  2. Utilizza l'API MediaStore per modificare o eliminare i file multimediali.

Importa una singola immagine già esistente

Quando vuoi importare una singola immagine già esistente (ad esempio, per utilizzare come foto per il profilo di un utente), la tua app può utilizzare la propria UI per operativa, oppure il selettore di sistema.

Presenta la tua interfaccia utente

Utilizza questo approccio:

  1. Seguendo le best practice descritte in Richiedere le autorizzazioni app, richiedi READ_EXTERNAL_STORAGE autorizzazione.
  2. Utilizza l'API query() per eseguire query su una raccolta multimediale.
  3. Visualizza i risultati nell'interfaccia utente personalizzata della tua app.

Utilizza il selettore di sistema

Utilizza l'intent ACTION_GET_CONTENT, che chiede all'utente di selezionare un'immagine da importare.

Se vuoi filtrare i tipi di immagini che il selettore di sistema presenta al un utente tra cui scegliere, puoi usare 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 la insert() per aggiungere record direttamente in MediaStore. Per ulteriori informazioni, vedi nella sezione Aggiungi un elemento del all'archiviazione dei contenuti multimediali.

Condividere file multimediali con un'app specifica

Usa il componente FileProvider di Android, come descritto nella sezione File di configurazione condivisione.

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.

In esecuzione su Android 11

Utilizza questo approccio:

  1. Seguendo le best practice descritte in Richiedere le autorizzazioni app, richiedi READ_EXTERNAL_STORAGE autorizzazione.
  2. 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 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:

  1. Seguendo le best practice descritte in Richiedi autorizzazioni app, richiedi l'autorizzazione WRITE_EXTERNAL_STORAGE.
  2. Accedi ai file utilizzando percorsi diretti.

Gestire i file non multimediali

Questa sezione descrive alcuni dei casi d'uso comuni per la gestione di file non multimediali. e illustra l'approccio generale che la tua app può usare. La tabella seguente riassume ciascuno di questi casi d'uso e fornisce i link a ognuna delle sezioni che contenere ulteriori dettagli.

Caso d'uso Riepilogo
Aprire il file di un documento Utilizza lo stesso approccio per tutte le versioni di Android.
Scrivere su file su volumi di archiviazione secondari Usa un unico approccio per Android 11. Utilizza un approccio diverso per le versioni precedenti di Android.
Eseguire la migrazione di file esistenti da una versione precedente posizione di archiviazione Se possibile, esegui la migrazione dei file all'archiviazione con ambito. Disattiva l'ambito per Android 10.
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 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.

Aprire un file di documento

Utilizza la ACTION_OPEN_DOCUMENT per chiedere all'utente di scegliere un file da aprire usando il selettore di sistema. Se vuoi filtrare i tipi di file che il selettore di sistema presenterà al un utente tra cui scegliere, puoi utilizzare setType() o EXTRA_MIME_TYPES.

Ad esempio, potresti trovare tutti i file PDF, ODT e TXT utilizzando il seguente codice:

KotlinJava
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
      )
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:

  1. Utilizza il modello di spazio di archiviazione basato sugli ambiti.
  2. Scegli come target Android 10 (livello API 29) o versioni precedenti.
  3. Dichiara il WRITE_EXTERNAL_STORAGE autorizzazione.
  4. Esegui uno dei seguenti tipi di accesso:
    • Accesso ai file con l'API MediaStore.
    • Accesso diretto al percorso del file utilizzando API come File o fopen().

In esecuzione su versioni precedenti

Utilizzare Storage Access Framework, che consente agli utenti di selezionare la posizione su un volume di archiviazione secondario in cui l'app può scrivere .

Eseguire la migrazione dei file esistenti da un percorso 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 i file in una posizione di archiviazione precedente, ti consigliamo di eseguire la migrazione dell'app in posizioni accessibili con l'archiviazione con ambito e apportare le modifiche necessarie all'app per funzionare con i file nello spazio di archiviazione con ambito.

Mantenere 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 lo spazio di archiviazione limitato. La dipende dal livello API target della tua app.

Se la tua app ha come target Android 11
  1. Imposta il parametro preserveLegacyExternalStorage flag a true per preservare lo spazio di archiviazione legacy modello in modo che che la tua app possa eseguire la migrazione dei dati di un utente quando esegue l'upgrade alla nuova versione di la tua app che ha come target Android 11.

  2. 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 la mantenere il comportamento dell'app nelle varie versioni di Android.

Esegui la migrazione dei dati dell'app

Quando la tua app è pronta per la migrazione, utilizza il seguente approccio:

  1. Target Android 10 o versioni precedenti.
  2. Disattiva lo spazio di archiviazione delimitato in modo che la tua app abbia accesso ai file di cui devi eseguire la migrazione.
  3. Esegui il deployment del codice che utilizza l'API File per spostare i file dalla loro posizione corrente in /sdcard/ a una posizione accessibile con lo spazio di archiviazione delimitato:

    1. Sposta tutti i file privati dell'app nella directory restituita dal getExternalFilesDir() .
    2. Sposta tutti i file non multimediali condivisi in una sottodirectory dedicata all'app di nella directory Downloads/.
  4. Rimuovi le directory di archiviazione precedenti dell'app dalla directory /sdcard/.

Dopo che gli utenti installano la nuova versione della tua app, completano i dati processo di migrazione sui propri dispositivi. Puoi monitorare il processo di migrazione alla base utenti creando un evento di analisi.

Dopo che gli utenti hanno eseguito la migrazione dei propri dati, pubblica un altro aggiornamento dell'app, dove hai come target Android 11.

Condividere contenuti con altre app

Per condividere i file di un'app con un'altra app, usa un FileProvider. Per le app che devono essere tutte condivise file tra loro, ti consigliamo di utilizzare una libreria di contenuti provider per ogni app. quindi sincronizzando 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 necessario da memorizzare nella cache.

Esportare file non multimediali su un dispositivo

Definisci una posizione predefinita adeguata per archiviare contenuti non multimediali . Consenti agli utenti di esportare file da directory specifiche dell'app in una posizione più accessibile a livello generale. Utilizza i download di MediaStore o le raccolte di documenti per esportare file non multimediali in del dispositivo.

Gestire file specifici per le app

Se la tua app crea file a cui altre app non devono accedere o non devono accedere, puoi archiviarli in località di archiviazione specifiche per l'app.

Directory della memoria interna

Il sistema impedisce ad altre app di accedere a queste posizioni. 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 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 l'app, i file salvati nello spazio di archiviazione specifico dell'app vengono rimosso, pertanto non dovresti usare questo spazio di archiviazione per salvare tutto ciò che l'utente si aspetta di conservare indipendentemente dalla tua app.

Disattiva temporaneamente l'archiviazione con ambito

Prima che la tua app sia completamente compatibile con lo spazio di archiviazione limitato, puoi disattivarla temporaneamente sia nei test sia nell'app di produzione.

Disattiva nei test

Su Android 10 (livello API 29) e versioni successive, i test della tua app vengono eseguiti in uno spazio di archiviazione la sandbox per impostazione predefinita. 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. Per farlo, aggiungi il seguente flag al harness pertinente che invoca am instrument:

-e no-isolated-storage 1

Questo flag influisce su tutto il comportamento del caso di test strumentato e su tutto il codice di test invocato. 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 estrarre la directory basata sull'app. Per determinare da quale directory estrarre i dati, chiama getExternalMediaDirs().

Disattiva nella tua 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 basato sugli ambiti nell'app di produzione. Tuttavia, 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 utilizzando l'archiviazione con ambito, puoi attivare il comportamento impostando il valore Da requestLegacyExternalStorage a false. Se stai eseguendo il test su un dispositivo che esegue Android 11, puoi anche utilizzare la compatibilità app per testare comportamento dell'app, con o senza spazio di archiviazione con ambito.

Risorse aggiuntive

Per ulteriori informazioni sullo spazio di archiviazione di Android, visualizza i seguenti materiali:

Blog post