Accesso al file system in Xamarin.iOS

Download Sample Scaricare l'esempio

È possibile usare Xamarin.iOS e le System.IO classi nella libreria di classi di base .NET per accedere al file system iOS. La classe File consente di creare, eliminare e leggere i file e la classe Directory consente di creare, eliminare o enumerare il contenuto delle directory. È anche possibile usare Stream sottoclassi, che possono fornire un maggiore grado di controllo sulle operazioni sui file, ad esempio la compressione o la ricerca di posizioni all'interno di un file.

iOS impone alcune restrizioni sulle operazioni che un'applicazione può eseguire con il file system per mantenere la sicurezza dei dati di un'applicazione e proteggere gli utenti da app maligne. Queste restrizioni fanno parte di Application Sandbox : un set di regole che limita l'accesso di un'applicazione a file, preferenze, risorse di rete, hardware e così via. Un'applicazione è limitata alla lettura e alla scrittura di file all'interno della home directory (percorso installato); non può accedere ai file di un'altra applicazione.

iOS include anche alcune funzionalità specifiche del file system: alcune directory richiedono un trattamento speciale rispetto ai backup e agli aggiornamenti e le applicazioni possono anche condividere file tra loro e l'app File (dal momento che iOS 11) e tramite iTunes.

Questo articolo illustra le funzionalità e le restrizioni del file system iOS e include un'applicazione di esempio che illustra come usare Xamarin.iOS per eseguire alcune semplici operazioni del file system:

A sample of iOS executing some simple file system operations

Accesso ai file generale

Xamarin.iOS consente di usare le classi .NET System.IO per le operazioni del file system in iOS.

I frammenti di codice seguenti illustrano alcune operazioni di file comuni. Tutti i file di SampleCode.cs sono disponibili nell'applicazione di esempio per questo articolo.

Uso delle directory

Questo codice enumera le sottodirectory nella directory corrente (specificata dal parametro "./"), ovvero il percorso del file eseguibile dell'applicazione. L'output sarà un elenco di tutti i file e le cartelle distribuiti con l'applicazione (visualizzata nella finestra della console durante il debug).

var directories = Directory.EnumerateDirectories("./");
foreach (var directory in directories) {
      Console.WriteLine(directory);
}

Lettura di file

Per leggere un file di testo, è necessaria una sola riga di codice. In questo esempio verrà visualizzato il contenuto di un file di testo nella finestra Output applicazione.

var text = File.ReadAllText("TestData/ReadMe.txt");
Console.WriteLine(text);

serializzazione XML

Anche se l'uso dello spazio dei nomi completo System.Xml non rientra nell'ambito di questo articolo, è possibile deserializzare facilmente un documento XML dal file system usando un oggetto StreamReader simile al frammento di codice seguente:

using (TextReader reader = new StreamReader("./TestData/test.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
      var xml = (MyObject)serializer.Deserialize(reader);
}

Per altre informazioni, vedere la documentazione relativa a System.Xml e serializzazione. Vedere la documentazione di Xamarin.iOS sul linker. Spesso è necessario aggiungere l'attributo [Preserve] alle classi che si intende serializzare.

Creazione di file e directory

Questo esempio illustra come usare la Environment classe per accedere alla cartella Documents in cui è possibile creare file e directory.

var documents =
 Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); 
var filename = Path.Combine (documents, "Write.txt");
File.WriteAllText(filename, "Write this text into a file");

La creazione di una directory è un processo simile:

var documents =
 Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine (documents, "NewDirectory");
Directory.CreateDirectory(directoryname);

Per altre informazioni, vedere le informazioni di riferimento sulle API System.IO.

Serializzazione di JSON

Json.NET è un framework JSON ad alte prestazioni che funziona con Xamarin.iOS ed è disponibile in NuGet. Aggiungere il pacchetto NuGet al progetto dell'applicazione usando Aggiungi NuGet in Visual Studio per Mac:

Adding the NuGet package to the applications project

Aggiungere quindi una classe per fungere da modello di dati per la serializzazione/deserializzazione (in questo caso Account.cs):

using System;
using System.Collections.Generic;
using Foundation; // for Preserve attribute, which helps serialization with Linking enabled

namespace FileSystem
{
    [Preserve]
    public class Account
    {
        public string Email { get; set; }
        public bool Active { get; set; }
        public DateTime CreatedDate { get; set; }
        public List<string> Roles { get; set; }

        public Account() {
        }
    }
}

Infine, creare un'istanza della Account classe , serializzarla in dati JSON e scriverla in un file:

// Create a new record
var account = new Account(){
    Email = "monkey@xamarin.com",
    Active = true,
    CreatedDate = new DateTime(2015, 5, 27, 0, 0, 0, DateTimeKind.Utc),
    Roles = new List<string> {"User", "Admin"}
};

// Serialize object
var json = JsonConvert.SerializeObject(account, Newtonsoft.Json.Formatting.Indented);

// Save to file
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine (documents, "account.json");
File.WriteAllText(filename, json);

Per altre informazioni sull'uso dei dati JSON in un'applicazione .NET, vedere la documentazione di Json.NET.

Considerazioni speciali

Nonostante le analogie tra le operazioni di file Xamarin.iOS e .NET, iOS e Xamarin.iOS differiscono da .NET in alcuni modi importanti.

Rendere accessibili i file di progetto in fase di esecuzione

Per impostazione predefinita, se si aggiunge un file al progetto, non verrà incluso nell'assembly finale e pertanto non sarà disponibile per l'applicazione. Per includere un file nell'assembly, è necessario contrassegnarlo con un'azione di compilazione speciale, denominata Contenuto.

Per contrassegnare un file per l'inclusione, fare clic con il pulsante destro del mouse sui file e scegliere Compila contenuto azione > in Visual Studio per Mac. È anche possibile modificare l'azione di compilazione nel foglio Proprietà del file.

Distinzione tra maiuscole e minuscole

È importante comprendere che il file system iOS fa distinzione tra maiuscole e minuscole. La distinzione tra maiuscole e minuscole indica che i nomi di file e directory devono corrispondere esattamente: README.txt e readme.txt verranno considerati nomi di file diversi.

Ciò potrebbe generare confusione per gli sviluppatori .NET che hanno più familiarità con il file system di Windows, ovvero senza distinzione tra maiuscole e minuscole: File, FILE e file fanno riferimento alla stessa directory.

Avviso

Il simulatore iOS non fa distinzione tra maiuscole e minuscole. Se la combinazione di maiuscole e minuscole del nome file è diversa tra il file stesso e i riferimenti al file nel codice, il codice potrebbe comunque funzionare nel simulatore, ma avrà esito negativo in un dispositivo reale. Questo è uno dei motivi per cui è importante distribuire e testare in anticipo un dispositivo effettivo e spesso durante lo sviluppo iOS.

Separatore di percorso

iOS usa la barra '/' come separatore di percorso (diversa da Windows, che usa la barra rovesciata '\').

A causa di questa differenza di confusione, è consigliabile usare il System.IO.Path.Combine metodo , che si adatta per la piattaforma corrente, anziché impostare come hardcode un particolare separatore di percorso. Si tratta di un passaggio semplice che rende il codice più portabile in altre piattaforme.

Sandbox dell'applicazione

L'accesso dell'applicazione al file system (e ad altre risorse, ad esempio le funzionalità di rete e hardware) è limitato per motivi di sicurezza. Questa restrizione è nota come sandbox dell'applicazione. In termini di file system, l'applicazione è limitata alla creazione e all'eliminazione di file e directory nella home directory.

La home directory è un percorso univoco nel file system in cui vengono archiviati l'applicazione e tutti i relativi dati. Non è possibile scegliere (o modificare) il percorso della home directory per l'applicazione; tuttavia iOS e Xamarin.iOS forniscono proprietà e metodi per gestire i file e le directory all'interno.

Bundle dell'applicazione

Il bundle dell'applicazione è la cartella che contiene l'applicazione. Si distingue dalle altre cartelle con il suffisso .app aggiunto al nome della directory. Il bundle dell'applicazione contiene il file eseguibile e tutto il contenuto (file, immagini e così via) necessario per il progetto.

Quando si passa al bundle dell'applicazione in Mac OS, viene visualizzato con un'icona diversa da quella visualizzata in altre directory (e il suffisso .app è nascosto). Tuttavia, si tratta semplicemente di una directory regolare che il sistema operativo visualizza in modo diverso.

Per visualizzare il bundle dell'applicazione per il codice di esempio, fare clic con il pulsante destro del mouse sul progetto in Visual Studio per Mac e selezionare Reveal in Finder. Passare quindi alla directory bin/ in cui si dovrebbe trovare un'icona dell'applicazione (simile allo screenshot seguente).

Navigate through the bin directory to find an application icon similar to this screenshot

Fare clic con il pulsante destro del mouse su questa icona e scegliere Mostra contenuto pacchetto per esplorare il contenuto della directory Bundle dell'applicazione. Il contenuto viene visualizzato esattamente come il contenuto di una directory regolare, come illustrato di seguito:

The contents of the app bundle

Il bundle dell'applicazione è ciò che viene installato nel simulatore o nel dispositivo durante i test e in definitiva è ciò che viene inviato ad Apple per l'inclusione nell'App Store.

Directory dell'applicazione

Quando l'applicazione viene installata in un dispositivo, il sistema operativo crea una home directory per l'applicazione e crea una serie di directory all'interno della directory radice dell'applicazione disponibili per l'uso. Poiché iOS 8, le directory accessibili dall'utente non si trovano all'interno della radice dell'applicazione, quindi non è possibile derivare i percorsi per il bundle dell'applicazione dalle directory utente o viceversa.

Queste directory, come determinare il percorso e i relativi scopi sono elencati di seguito:

 

Directory Descrizione
[ApplicationName].app/ In iOS 7 e versioni precedenti si tratta della directory in cui è archiviato l'eseguibile ApplicationBundle dell'applicazione. La struttura di directory creata nell'app esiste in questa directory, ad esempio immagini e altri tipi di file contrassegnati come Risorse nel progetto Visual Studio per Mac.

Se è necessario accedere ai file di contenuto all'interno del bundle dell'applicazione, il percorso di questa directory è disponibile tramite la NSBundle.MainBundle.BundlePath proprietà .
Documenti/ Usare questa directory per archiviare documenti utente e file di dati dell'applicazione.

Il contenuto di questa directory può essere reso disponibile all'utente tramite la condivisione file di iTunes (anche se questa opzione è disabilitata per impostazione predefinita). Aggiungere una UIFileSharingEnabled chiave booleana al file Info.plist per consentire agli utenti di accedere a questi file.

Anche se un'applicazione non abilita immediatamente la condivisione file, è consigliabile evitare di inserire file che devono essere nascosti agli utenti in questa directory (ad esempio i file di database, a meno che non si intenda condividerli). Se i file sensibili rimangono nascosti, questi file non verranno esposti (e potenzialmente spostati, modificati o eliminati da iTunes) se la condivisione file è abilitata in una versione futura.

È possibile usare il Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) metodo per ottenere il percorso della directory Documents per l'applicazione.

Il contenuto di questa directory viene eseguito il backup da iTunes.
Libreria/ La directory Libreria è un buon punto in cui archiviare i file che non vengono creati direttamente dall'utente, ad esempio database o altri file generati dall'applicazione. Il contenuto di questa directory non viene mai esposto all'utente tramite iTunes.

È possibile creare sottodirectory personalizzate in Libreria; Tuttavia, ci sono già alcune directory create dal sistema in cui è necessario essere a conoscenza, tra cui Preferenze e Cache.

Il contenuto di questa directory ,ad eccezione della sottodirectory Caches, viene eseguito il backup da iTunes. Verrà eseguito il backup delle directory personalizzate create nella libreria.
Libreria/Preferenze/ I file di preferenza specifici dell'applicazione vengono archiviati in questa directory. Non creare direttamente questi file. Usare invece la NSUserDefaults classe .

Il contenuto di questa directory viene eseguito il backup da iTunes.
Libreria/Cache/ La directory Caches è un buon punto di riferimento per archiviare i file di dati che possono essere utili per l'esecuzione dell'applicazione, ma che possono essere facilmente ricreati. L'applicazione deve creare ed eliminare questi file in base alle esigenze ed essere in grado di ricreare questi file, se necessario. iOS 5 può anche eliminare questi file (in situazioni di archiviazione insufficiente), ma non lo farà durante l'esecuzione dell'applicazione.

Il contenuto di questa directory non viene eseguito il backup da iTunes, il che significa che non saranno presenti se l'utente ripristina un dispositivo e potrebbe non essere presente dopo l'installazione di una versione aggiornata dell'applicazione.

Ad esempio, nel caso in cui l'applicazione non possa connettersi alla rete, è possibile usare la directory Caches per archiviare dati o file per offrire un'esperienza offline ottimale. L'applicazione può salvare e recuperare questi dati rapidamente durante l'attesa delle risposte di rete, ma non è necessario eseguirne il backup e può essere facilmente ripristinato o ricreato dopo un ripristino o un aggiornamento della versione.
Tmp/ Le applicazioni possono archiviare file temporanei necessari solo per un breve periodo in questa directory. Per risparmiare spazio, i file devono essere eliminati quando non sono più necessari. Il sistema operativo può anche eliminare file da questa directory quando un'applicazione non è in esecuzione.

Il contenuto di questa directory non viene eseguito il backup da iTunes.

Ad esempio, la directory tmp potrebbe essere usata per archiviare i file temporanei scaricati per la visualizzazione all'utente (ad esempio avatar di Twitter o allegati di posta elettronica), ma che potrebbero essere eliminati una volta visualizzati (e scaricati di nuovo se sono necessari in futuro).

Questo screenshot mostra la struttura di directory in una finestra finder:

This screenshot shows the directory structure in a Finder window

Accesso ad altre directory a livello di codice

Gli esempi di directory e file precedenti hanno eseguito l'accesso alla Documents directory. Per scrivere in un'altra directory, è necessario costruire un percorso usando la sintassi ".". come illustrato di seguito:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var library = Path.Combine (documents, "..", "Library");
var filename = Path.Combine (library, "WriteToLibrary.txt");
File.WriteAllText(filename, "Write this text into a file in Library");

La creazione di una directory è simile alla seguente:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var library = Path.Combine (documents, "..", "Library");
var directoryname = Path.Combine (library, "NewLibraryDirectory");
Directory.CreateDirectory(directoryname);

I percorsi delle Caches directory e tmp possono essere costruiti come segue:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var cache = Path.Combine (documents, "..", "Library", "Caches");
var tmp = Path.Combine (documents, "..", "tmp");

Condivisione con l'app File

iOS 11 ha introdotto l'app File : un browser di file per iOS che consente all'utente di visualizzare e interagire con i propri file in iCloud e archiviati anche da qualsiasi applicazione che la supporta. Per consentire all'utente di accedere direttamente ai file nell'app, creare una nuova chiave booleana nel file LSSupportsOpeningDocumentsInPlace Info.plist e impostarla truesu , come indicato di seguito:

Set LSSupportsOpeningDocumentsInPlace in Info.plist

La directory Documenti dell'app sarà ora disponibile per l'esplorazione nell'app File. Nell'app File passare a On My i Telefono e ogni app con file condivisi sarà visibile. Gli screenshot seguenti mostrano l'aspetto dell'app di esempio FileSystem:

iOS 11 Files appBrowse my iPhone filesSample app files

Condivisione di file con l'utente tramite iTunes

Gli utenti possono accedere ai file nella directory Documenti dell'applicazione modificando Info.plist e creando un'applicazione che supporta la voce di condivisione iTunes (UIFileSharingEnabled) nella visualizzazione Origine , come illustrato di seguito:

Adding the Application supports iTunes sharing property

Questi file possono essere accessibili in iTunes quando il dispositivo è connesso e l'utente sceglie la Apps scheda. Ad esempio, lo screenshot seguente mostra i file nell'app selezionata condivisi tramite iTunes:

This screenshot shows the files in selected app shared via iTunes

Gli utenti possono accedere solo agli elementi di primo livello in questa directory tramite iTunes. Non possono visualizzare il contenuto di alcuna sottodirectory (anche se possono copiarli nel computer o eliminarli). Ad esempio, con i file GoodReader, PDF e EPUB possono essere condivisi con l'applicazione in modo che gli utenti possano leggerli nei dispositivi iOS.

Gli utenti che modificano il contenuto della cartella Documenti possono causare problemi se non sono attenti. L'applicazione deve prendere in considerazione questo aspetto e essere resiliente agli aggiornamenti distruttivi della cartella Documenti.

Il codice di esempio per questo articolo crea sia un file che una cartella nella cartella Documenti (in SampleCode.cs) e abilita la condivisione file nel file Info.plist . Questo screenshot mostra come vengono visualizzati in iTunes:

This screenshot shows how the files appear in iTunes

Per informazioni su come impostare le icone per l'applicazione e per i tipi di documento personalizzati creati, vedere l'articolo Uso delle immagini .

Se la chiave è false o non è presente, la UIFileSharingEnabled condivisione file è, per impostazione predefinita, disabilitata e gli utenti non potranno interagire con la directory Documenti.

Backup e ripristino

Quando viene eseguito il backup di un dispositivo da iTunes, tutte le directory create nella home directory dell'applicazione verranno salvate tranne le directory seguenti:

  • [ApplicationName].app : non scrivere in questa directory, perché è firmato e quindi deve rimanere invariato dopo l'installazione. Può contenere risorse a cui si accede dal codice, ma non richiedono il backup perché vengono ripristinate scaricando nuovamente l'app.
  • Libreria/Cache: la directory della cache è destinata ai file di lavoro di cui non è necessario eseguire il backup.
  • tmp : questa directory viene usata per i file temporanei creati ed eliminati quando non sono più necessari o per i file eliminati da iOS quando è necessario spazio.

Il backup di una grande quantità di dati può richiedere molto tempo. Se si decide di eseguire il backup di qualsiasi documento o dati specifico, l'applicazione deve usare le cartelle Documenti e raccolta. Per i dati temporanei o i file che possono essere facilmente recuperati dalla rete, usare cache o la directory tmp.

Nota

iOS "pulisce" il file system quando un dispositivo viene eseguito in modo critico sullo spazio su disco. Questo processo rimuoverà tutti i file dalla cartella Library/Caches e tmp delle applicazioni attualmente in esecuzione.

Conformità alle restrizioni di backup di iOS 5 iCloud

Nota

Anche se questo criterio è stato introdotto per la prima volta con iOS 5 (che sembra molto tempo fa) le linee guida sono ancora rilevanti per le app oggi.

Apple ha introdotto la funzionalità iCloud Backup con iOS 5. Quando backup di iCloud è abilitato, tutti i file nella home directory dell'applicazione (escluse le directory di cui normalmente non viene eseguito il backup, ad esempio il bundle dell'app, Cachese tmp) vengono sottoposti a backup nei server iCloud. Questa funzionalità fornisce all'utente un backup completo nel caso in cui il dispositivo venga smarrito, rubato o danneggiato.

Poiché iCloud offre solo 5 GB di spazio libero per ogni utente e per evitare inutilmente l'uso della larghezza di banda, Apple prevede che le applicazioni esebitino solo i dati essenziali generati dall'utente. Per rispettare le linee guida per iOS Data Archiviazione, è necessario limitare la quantità di dati di cui viene eseguito il backup rispettando gli elementi seguenti:

  • Archiviare solo i dati generati dall'utente o i dati che altrimenti non possono essere ricreati, nella directory Documents (di cui viene eseguito il backup).
  • Archiviare tutti gli altri dati che possono essere facilmente ricreati o scaricati nuovamente in Library/Caches o tmp (che non viene eseguito il backup e possono essere "puliti").
  • Se si dispone di file che potrebbero essere appropriati per la Library/Caches cartella o tmp ma non si vuole essere "puliti", archiviarli altrove (ad esempio Library/YourData) e applicare l'attributo "non eseguire il backup" per impedire ai file di usare la larghezza di banda e lo spazio di archiviazione di iCloud Backup. Questi dati usano ancora spazio sul dispositivo, quindi è consigliabile gestirli attentamente ed eliminarli quando possibile.

L'attributo 'do not backup' viene impostato usando la NSFileManager classe . Verificare che la classe sia using Foundation e chiamare SetSkipBackupAttribute come segue:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine (documents, "LocalOnly.txt");
File.WriteAllText(filename, "This file will never get backed-up. It would need to be re-created after a restore or re-install");
NSFileManager.SetSkipBackupAttribute (filename, true); // backup will be skipped for this file

Quando SetSkipBackupAttribute il true file non verrà eseguito il backup, indipendentemente dalla directory in cui è archiviato (anche la Documents directory). È possibile eseguire una query sull'attributo usando il GetSkipBackupAttribute metodo ed è possibile reimpostarlo chiamando il SetSkipBackupAttribute metodo con false, come illustrato di seguito:

NSFileManager.SetSkipBackupAttribute (filename, false); // file will be backed-up

Condivisione dei dati tra app iOS ed estensioni dell'app

Poiché le estensioni dell'app vengono eseguite come parte di un'applicazione host (anziché l'app contenitore), la condivisione dei dati non è inclusa automaticamente, quindi è necessario un lavoro aggiuntivo. I gruppi di app sono il meccanismo usato da iOS per consentire a app diverse di condividere i dati. Se le applicazioni sono state configurate correttamente con i diritti e il provisioning corretti, possono accedere a una directory condivisa al di fuori della normale sandbox iOS.

Configurare un gruppo di app

Il percorso condiviso viene configurato usando un gruppo di app, configurato nella sezione Certificati, Identificatori e profili in iOS Dev Center. Questo valore deve anche essere fatto riferimento in Entitlements.plist di ogni progetto.

Per informazioni sulla creazione e la configurazione di un gruppo di app, vedere la guida Alle funzionalità del gruppo di app.

File

L'app iOS e l'estensione possono anche condividere file usando un percorso di file comune (dato che sono stati configurati correttamente con i diritti e il provisioning corretti):

var FileManager = new NSFileManager ();
var appGroupContainer =FileManager.GetContainerUrl ("group.com.xamarin.WatchSettings");
var appGroupContainerPath = appGroupContainer.Path

Console.WriteLine ("Group Path: " + appGroupContainerPath);

// use the path to create and update files
...

Importante

Se il percorso del gruppo restituito è null, controllare la configurazione dei diritti e del profilo di provisioning e assicurarsi che siano corretti.

Aggiornamenti della versione dell'applicazione

Quando viene scaricata una nuova versione dell'applicazione, iOS crea una nuova home directory e archivia il nuovo bundle di applicazioni. iOS sposta quindi le cartelle seguenti dalla versione precedente del bundle dell'applicazione alla nuova home directory:

  • Documenti
  • Libreria

Anche altre directory possono essere copiate e inserite nella nuova home directory, ma non è garantito che vengano copiate, quindi l'applicazione non deve basarsi su questo comportamento di sistema.

Riepilogo

Questo articolo ha mostrato che le operazioni del file system con Xamarin.iOS sono simili a qualsiasi altra applicazione .NET. Ha anche introdotto la sandbox dell'applicazione ed esaminato le implicazioni di sicurezza che causa. Successivamente, è stato esaminato il concetto di bundle di applicazioni. Infine, enumerò le directory specializzate disponibili per l'applicazione e ne spiegò i ruoli durante gli aggiornamenti e i backup dell'applicazione.