File Archiviazione e Accesso con Xamarin.Android

Un requisito comune per le app Android consiste nel modificare i file: il salvataggio di immagini, il download di documenti o l'esportazione di dati da condividere con altri programmi. Android (basato su Linux) supporta questa funzionalità fornendo spazio per l'archiviazione file. Android raggruppa il file system in due diversi tipi di archiviazione:

  • Archiviazione interna: si tratta di una parte del file system accessibile solo dall'applicazione o dal sistema operativo.
  • External Archiviazione: si tratta di una partizione per l'archiviazione di file accessibili da tutte le app, dall'utente e possibilmente da altri dispositivi. In alcuni dispositivi, l'archiviazione esterna può essere rimovibile ,ad esempio una scheda SD.

Questi raggruppamenti sono solo concettuali e non fanno necessariamente riferimento a una singola partizione o directory nel dispositivo. Un dispositivo Android fornirà sempre la partizione per l'archiviazione interna e l'archiviazione esterna. È possibile che alcuni dispositivi abbiano più partizioni considerate come risorse di archiviazione esterne. Indipendentemente dalla partizione, le API per la lettura, la scrittura o la creazione di file sono le stesse. Esistono due set di API che possono essere usate da un'applicazione Xamarin.Android per l'accesso ai file:

  1. Le API .NET (fornite da Mono e incapsulate da Xamarin.Android) includono gli helper del file system forniti da Xamarin.Essentials. Le API .NET offrono la migliore compatibilità multipiattaforma e, di conseguenza, l'attenzione di questa guida sarà su queste API.
  2. Api di accesso ai file Java native (fornite da Java e incapsulate da Xamarin.Android): Java offre api personalizzate per la lettura e la scrittura di file. Si tratta di un'alternativa completamente accettabile alle API .NET, ma sono specifiche di Android e non sono adatte per le app destinate a essere multipiattaforma.

La lettura e la scrittura nei file sono quasi identiche in Xamarin.Android, così come per qualsiasi altra applicazione .NET. L'app Xamarin.Android determina il percorso del file che verrà modificato, quindi usa idiomi .NET standard per l'accesso ai file. Poiché i percorsi effettivi dell'archiviazione interna ed esterna possono variare dal dispositivo al dispositivo o dalla versione android alla versione android, non è consigliabile impostare come hardcoded il percorso dei file. Usare invece le API Xamarin.Android per determinare il percorso dei file. In questo modo, le API .NET per la lettura e la scrittura di file espongono le API Android native che consentiranno di determinare il percorso dei file nell'archiviazione interna ed esterna.

Prima di discutere delle API coinvolte nell'accesso ai file, è importante comprendere alcuni dei dettagli che circondano l'archiviazione interna ed esterna. Questa operazione verrà illustrata nella sezione successiva.

Archiviazione interna e esterna

Concettualmente, l'archiviazione interna e l'archiviazione esterna sono molto simili. Si tratta di entrambe le posizioni in cui un'app Xamarin.Android può salvare i file. Questa somiglianza può generare confusione per gli sviluppatori che non hanno familiarità con Android perché non è chiaro quando un'app deve usare l'archiviazione interna o l'archiviazione esterna.

L'archiviazione interna si riferisce alla memoria non volatile allocata da Android al sistema operativo, alle API e alle singole app. Questo spazio non è accessibile ad eccezione del sistema operativo o delle app. Android allocherà una directory nella partizione di archiviazione interna per ogni app. Quando l'app viene disinstallata, verranno eliminati anche tutti i file mantenuti nello spazio di archiviazione interno in tale directory. L'archiviazione interna è più adatta per i file accessibili solo all'app e che non verranno condivisi con altre app o avranno un valore molto minimo dopo la disinstallazione dell'app. In Android 6.0 o versione successiva, è possibile eseguire automaticamente il backup dei file nella risorsa di archiviazione interna tramite Google usando la funzionalità Backup automatico in Android 6.0. L'archiviazione interna presenta gli svantaggi seguenti:

  • I file non possono essere condivisi.
  • I file verranno eliminati quando l'app viene disinstallata.
  • Lo spazio disponibile nell'archiviazione interna potrebbe essere limitato.

L'archiviazione esterna si riferisce all'archiviazione file che non è una risorsa di archiviazione interna e non è accessibile esclusivamente a un'app. Lo scopo principale dell'archiviazione esterna è quello di fornire una posizione in cui inserire i file che devono essere condivisi tra app o troppo grandi per adattarsi allo spazio di archiviazione interno. Il vantaggio dell'archiviazione esterna è che in genere ha molto più spazio per i file rispetto all'archiviazione interna. Tuttavia, l'archiviazione esterna non è sempre garantita per essere presente in un dispositivo e potrebbe richiedere un'autorizzazione speciale da parte dell'utente per accedervi.

Nota

Per i dispositivi che supportano più utenti, Android fornirà a ogni utente la propria directory sia nella risorsa di archiviazione interna che esterna. Questa directory non è accessibile ad altri utenti nel dispositivo. Questa separazione è invisibile alle app, purché non siano percorsi hardcoded per i file in una risorsa di archiviazione interna o esterna.

Come regola generale, le app Xamarin.Android devono preferire salvare i file nell'archiviazione interna quando è ragionevole e basarsi sull'archiviazione esterna quando i file devono essere condivisi con altre app, sono molto grandi o devono essere conservati anche se l'app viene disinstallata. Ad esempio, un file di configurazione è più adatto per una risorsa di archiviazione interna perché non ha importanza, ad eccezione dell'app che lo crea. Al contrario, le foto sono un buon candidato per l'archiviazione esterna. Possono essere molto grandi e in molti casi l'utente potrebbe voler condividerli o accedervi anche se l'app viene disinstallata.

Questa guida si concentrerà sull'archiviazione interna. Vedere la guida Archiviazione esterna per informazioni dettagliate sull'uso dell'archiviazione esterna in un'applicazione Xamarin.Android.

Uso dell'archiviazione interna

La directory di archiviazione interna per un'applicazione è determinata dal sistema operativo ed è esposta alle app Android dalla Android.Content.Context.FilesDir proprietà . Verrà restituito un Java.IO.File oggetto che rappresenta la directory che Android ha dedicato esclusivamente per l'app. Ad esempio, un'app con il nome del pacchetto com.companyname la directory di archiviazione interna potrebbe essere:

/data/user/0/com.companyname/files

Questo documento farà riferimento alla directory di archiviazione interna come INTERNAL_STORAGE.

Importante

Il percorso esatto della directory di archiviazione interna può variare da dispositivo a dispositivo e tra le versioni di Android. Per questo motivo, le app non devono impostare come hardcoded il percorso della directory di archiviazione dei file interni e usare invece le API Xamarin.Android, ad esempio System.Environment.GetFolderPath().

Per ottimizzare la condivisione del codice, le app Xamarin.Android (o le app Xamarin.Forms destinate a Xamarin.Android) devono usare il System.Environment.GetFolderPath() metodo . In Xamarin.Android questo metodo restituirà una stringa per una directory che corrisponde alla stessa posizione di Android.Content.Context.FilesDir. Questo metodo accetta un'enumerazione , System.Environment.SpecialFolderutilizzata per identificare un set di costanti enumerate che rappresentano i percorsi di cartelle speciali utilizzate dal sistema operativo. Non tutti i System.Environment.SpecialFolder valori verranno mappati a una directory valida in Xamarin.Android. La tabella seguente descrive il percorso previsto per un determinato valore di System.Environment.SpecialFolder:

System.Environment.SpecialFolder Percorso
ApplicationData INTERNAL_STORAGE/.config
Desktop INTERNAL_STORAGE/desktop
LocalApplicationData INTERNAL_STORAGE/.local/share
MyDocuments INTERNAL_STORAGE
MyMusic INTERNAL_STORAGE/Musica
MyPictures INTERNAL_STORAGE/immagini
MyVideos INTERNAL_STORAGE/Video
Personal INTERNAL_STORAGE
Fonts INTERNAL_STORAGE/.fonts
Templates INTERNAL_STORAGE/modelli
CommonApplicationData /usr/share
CommonApplicationData /usr/share

Lettura o scrittura in file nella risorsa di archiviazione interna

Tutte le API C# per la scrittura in un file sono sufficienti. Tutto ciò che è necessario consiste nel ottenere il percorso del file che si trova nella directory allocata all'applicazione. È consigliabile usare le versioni asincrone delle API .NET per ridurre al minimo eventuali problemi che possono essere associati all'accesso ai file che bloccano il thread principale.

Questo frammento di codice è un esempio di scrittura di un numero intero in un file di testo UTF-8 nella directory di archiviazione interna di un'applicazione:

public async Task SaveCountAsync(int count)
{
    var backingFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "count.txt");
    using (var writer = File.CreateText(backingFile))
    {
        await writer.WriteLineAsync(count.ToString());
    }
}

Il frammento di codice successivo consente di leggere un valore intero archiviato in un file di testo:

public async Task<int> ReadCountAsync()
{
    var backingFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "count.txt");

    if (backingFile == null || !File.Exists(backingFile))
    {
        return 0;
    }

    var count = 0;
    using (var reader = new StreamReader(backingFile, true))
    {
        string line;
        while ((line = await reader.ReadLineAsync()) != null)
        {
            if (int.TryParse(line, out var newcount))
            {
                count = newcount;
            }
        }
    }

    return count;
}

Uso di Xamarin.Essentials - Helper del file system

Xamarin.Essentials è un set di API per la scrittura di codice compatibile con più piattaforme. Gli helper del file system sono una classe che contiene una serie di helper per semplificare l'individuazione delle directory dati e della cache dell'applicazione. Questo frammento di codice fornisce un esempio di come trovare la directory di archiviazione interna e la directory della cache per un'app:

// Get the path to a file on internal storage
var backingFile = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, "count.txt");

// Get the path to a file in the cache directory
var cacheFile = Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, "count.txt");

Nascondere i file dal MediaStore

MediaStore è un componente Android che raccoglie metadati sui file multimediali (video, musica, immagini) in un dispositivo Android. Lo scopo è semplificare la condivisione di questi file in tutte le app Android nel dispositivo.

I file privati non verranno visualizzati come supporti condivisibili. Ad esempio, se un'app salva un'immagine nell'archiviazione esterna privata, tale file non verrà prelevato dallo scanner multimediale (MediaStore).

I file pubblici verranno prelevati da MediaStore. Directory con un nome di file di byte zero. NOMEDIA non verrà analizzata da MediaStore.