Acceso al sistema de archivos en Xamarin.iOS
Puede usar Xamarin.iOS y las clases de System.IO
en la biblioteca de clases base (BCL) de .NET para acceder al sistema de archivos iOS. La clase File
le permite crear, eliminar y leer archivos, mientras que la clase Directory
le permite crear, eliminar o enumerar el contenido de directorios. También puede usar la subclases de Stream
, que pueden proporcionar un mayor nivel de control sobre las operaciones de archivo (como la compresión o la búsqueda de ubicaciones en un archivo).
iOS impone algunas restricciones sobre lo que una aplicación puede hacer con el sistema de archivos para conservar la seguridad de los datos de una aplicación y para proteger a los usuarios de aplicaciones maliciosas. Estas restricciones forman parte de espacio aislado de aplicaciones, un conjunto de reglas que limita el acceso de una aplicación a archivos, preferencias, recursos de red, hardware, etc. Una aplicación se limita a leer y escribir archivos dentro de su directorio principal (ubicación instalada); no puede acceder a otros archivos de la aplicación.
iOS también tiene algunas características específicas del sistema de archivos: ciertos directorios requieren un tratamiento especial con respecto a las copias de seguridad y las actualizaciones, y las aplicaciones también pueden compartir archivos entre sí y la aplicación Files (desde iOS 11) y a través de iTunes.
En este artículo se describen las características y restricciones del sistema de archivos de iOS e se incluye una aplicación de ejemplo que muestra cómo se debe usar Xamarin.iOS para ejecutar algunas operaciones sencillas del sistema de archivos:
Acceso general a archivos
Xamarin.iOS permite usar las clases de System.IO
de .NET para las operaciones del sistema de archivos en iOS.
En los fragmentos de código siguientes se muestran algunas operaciones de archivo comunes. Las encontrarás a continuación en el archivo SampleCode.cs, en la aplicación de ejemplo de este artículo.
Trabajar con directorios
Este código enumera los subdirectorios del directorio actual (especificado por el parámetro "./"), que es la ubicación del archivo ejecutable de la aplicación. El resultado será una lista de todos los archivos y carpetas que se implementan con la aplicación (que se muestran en la ventana de la consola mientras se depura).
var directories = Directory.EnumerateDirectories("./");
foreach (var directory in directories) {
Console.WriteLine(directory);
}
Lectura de archivos
Para leer un archivo de texto, solo necesita una sola línea de código. En este ejemplo se mostrará el contenido de un archivo de texto en la ventana Resultado de la aplicación.
var text = File.ReadAllText("TestData/ReadMe.txt");
Console.WriteLine(text);
serialización XML
Aunque trabajar con el espacio de nombres de System.Xml
completo está fuera del ámbito de este artículo, puede deserializar fácilmente un documento XML desde el sistema de archivos mediante StreamReader como este fragmento de código:
using (TextReader reader = new StreamReader("./TestData/test.xml")) {
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
var xml = (MyObject)serializer.Deserialize(reader);
}
Para obtener más información, consulte la documentación de System.Xml y serialización. Consulte la documentación de Xamarin.iOS en el enlazador; a menudo, tendrá que agregar el atributo de [Preserve]
a las clases que pretende serializar.
Creación de archivos y directorios
En este ejemplo se muestra cómo usar la clase Environment
para acceder a la carpeta Documentos en la que podemos crear archivos y directorios.
var documents =
Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine (documents, "Write.txt");
File.WriteAllText(filename, "Write this text into a file");
La creación de un directorio es un proceso similar:
var documents =
Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine (documents, "NewDirectory");
Directory.CreateDirectory(directoryname);
Para más información, consulte la referencia de API de System.IO.
Serialización de JSON
Json.NET es un marco JSON de alto rendimiento que funciona con Xamarin.iOS y está disponible en NuGet. Agregue el paquete NuGet al proyecto de aplicación mediante Agregar NuGet en Visual Studio para Mac:
A continuación, agregue una clase para que actúe como modelo de datos para la serialización o deserialización (en este 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() {
}
}
}
Por último, cree una instancia de la clase Account
, serialícela en datos JSON y escríbala en un archivo:
// 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);
Para obtener más información sobre cómo trabajar con datos JSON en una aplicación .NET, consulte la documentación de Json.NET.
Consideraciones especiales
A pesar de las similitudes entre las operaciones de archivos de Xamarin.iOS y .NET, iOS y Xamarin.iOS difieren de .NET de algunas maneras importantes.
Hacer que los archivos del proyecto sean accesibles en tiempo de ejecución
De forma predeterminada, si agrega un archivo al proyecto, no se incluirá en el ensamblado final y, por tanto, no estará disponible para la aplicación. Para incluir un archivo en el ensamblado, debe marcarlo con una acción de compilación especial, denominada Contenido.
Para marcar un archivo para su inclusión, haga clic con el botón derecho en los archivos y elija Acción de compilación > Contenido en Visual Studio para Mac. También puede cambiar la Acción de compilación en la hoja Propiedades del archivo.
Distinción de mayúsculas y minúsculas
Es importante comprender que el sistema de archivos de iOS distingue mayúsculas de minúsculas. La distinción entre mayúsculas y minúsculas significa que los nombres de archivos y directorios deben coincidir exactamente: README.txt y readme.txt se considerarían nombres de archivo diferentes.
Esto podría resultar confuso para los desarrolladores de .NET que están más familiarizados con el sistema de archivos de Windows, que no distingue mayúsculas de minúsculas: Archivos, ARCHIVOS y archivos harían referencia al mismo directorio.
Advertencia
El simulador de iOS NO distingue mayúsculas de minúsculas. Si el uso de mayúsculas y minúsculas del nombre del archivo difiere entre el propio archivo y las referencias a él en el código, es posible que el código siga funcionando en el simulador, pero se producirá un error en un dispositivo real. Esta es una de las razones por las que es importante implementar y probar en un dispositivo real al principio y, a menudo, durante el desarrollo de iOS.
Separador de rutas
iOS usa la barra diagonal '/' como separador de rutas de acceso (que es diferente de Windows, que usa la barra diagonal inversa '\').
Debido a esta diferencia confusa, se recomienda usar el método de System.IO.Path.Combine
, que se ajusta para la plataforma actual, en lugar de codificar de forma dura un separador de ruta de acceso determinado. Este es un paso sencillo que hace que el código sea más portátil para otras plataformas.
Espacio aislado de aplicaciones
El acceso de la aplicación al sistema de archivos (y otros recursos, como las características de red y hardware) está limitado por motivos de seguridad. Esta restricción se conoce como espacio aislado de aplicaciones. En términos del sistema de archivos, la aplicación se limita a crear y eliminar archivos y directorios en su directorio principal.
El directorio principal es una ubicación única en el sistema de archivos donde se almacenan la aplicación y todos sus datos. No puede elegir (ni cambiar) la ubicación del directorio principal de la aplicación; sin embargo, iOS y Xamarin.iOS proporcionan propiedades y métodos para administrar los archivos y directorios dentro.
Agrupación de aplicaciones
El paquete de aplicaciones es la carpeta que contiene la aplicación. Se distingue de otras carpetas al agregar el sufijo .app al nombre del directorio. La agrupación de aplicaciones contiene el archivo ejecutable y todo el contenido (archivos, imágenes, etc.) necesarios para el proyecto.
Cuando navega a la agrupación de aplicaciones en Mac OS, aparece con un icono diferente al que ve en otros directorios (y el sufijo .app está oculto); sin embargo, es solo un directorio normal que el sistema operativo muestra de forma diferente.
Para ver la agrupación de aplicaciones del código de ejemplo, haga clic con el botón derecho en el proyecto en Visual Studio para Mac y seleccione Mostrar en Finder. A continuación, vaya al directorio bin/ donde debe encontrar un icono de aplicación (similar a la captura de pantalla siguiente).
Haga clic con el botón derecho en este icono y elija Mostrar contenido del paquete para examinar el contenido del directorio Agrupación de aplicaciones. El contenido aparece igual que el contenido de un directorio normal, como se muestra aquí:
La agrupación de aplicaciones es lo que se instala en el simulador o en el dispositivo durante las pruebas y, en última instancia, es lo que se envía a Apple para su inclusión en App Store.
Directorios de aplicaciones
Cuando la aplicación se instala en un dispositivo, el sistema operativo crea un directorio principal para la aplicación y un número de directorios dentro del directorio raíz de la aplicación que están disponibles para su uso. Desde iOS 8, los directorios accesibles para el usuario NO se encuentran dentro de la raíz de la aplicación, por lo que no puede derivar las rutas de acceso para la agrupación de aplicaciones de los directorios de usuario o viceversa.
Estos directorios, el modo de determinar su ruta de acceso y sus propósitos se enumeran a continuación:
Directorio | Descripción |
---|---|
[ApplicationName].app/ | En iOS 7 y versiones anteriores, este es el directorio ApplicationBundle donde se almacena el ejecutable de la aplicación. La estructura de directorios que crea en la aplicación existe en este directorio (por ejemplo, imágenes y otros tipos de archivo que ha marcado como Recursos en el proyecto de Visual Studio para Mac).Si necesita acceder a los archivos de contenido dentro de la agrupación de aplicaciones, la ruta de acceso a este directorio está disponible a través de la propiedad NSBundle.MainBundle.BundlePath . |
Documentos/ | Use este directorio para almacenar documentos de usuario y archivos de datos de la aplicación. El contenido de este directorio se puede poner a disposición del usuario a través del uso compartido de archivos de iTunes (aunque esta opción está deshabilitada de forma predeterminada). Agregue una clave booleana UIFileSharingEnabled al archivo Info.plist para permitir que los usuarios accedan a estos archivos.Incluso si una aplicación no habilita inmediatamente el uso compartido de archivos, debe evitar colocar archivos que deben ocultarse a los usuarios de este directorio (como archivos de base de datos, a menos que quiera compartirlos). Siempre que los archivos confidenciales permanezcan ocultos, estos archivos no se expondrán (y iTunes no los moverá, modificará ni eliminará) si el uso compartido de archivos está habilitado en una versión futura. Puede usar el método Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) para obtener la ruta de acceso al directorio Documentos de la aplicación.iTunes realiza una copia de seguridad del contenido de este directorio. |
Biblioteca/ | El directorio Biblioteca es un buen lugar para almacenar archivos que el usuario no crea directamente, como bases de datos u otros archivos generados por la aplicación. El contenido de este directorio nunca se expone al usuario a través de iTunes. Puede crear sus propios subdirectorios en Biblioteca; sin embargo, ya hay algunos directorios creados por el sistema que debe tener en cuenta, incluidas las preferencias y las cachés. iTunes realiza una copia de seguridad del contenido de este directorio (excepto el subdirectorio Cachés). Se realizará una copia de seguridad de los directorios personalizados que cree en Biblioteca. |
Biblioteca/Preferencias/ | Los archivos de preferencias específicos de la aplicación se almacenan en este directorio. No cree estos archivos directamente. Utilice la clase NSUserDefaults en su lugar.iTunes realiza una copia de seguridad del contenido de este directorio. |
Biblioteca/cachés/ | El directorio Cachés es un buen lugar para almacenar archivos de datos que pueden ayudar a la ejecución de la aplicación, pero que se pueden volver a crear fácilmente. La aplicación debe crear y eliminar estos archivos según sea necesario y poder volver a crear estos archivos si es necesario. iOS 5 también puede eliminar estos archivos (en situaciones de almacenamiento bajo), pero no lo hará mientras se ejecuta la aplicación. iTunes no realiza una copia de seguridad del contenido de este directorio, lo que significa que no estarán presentes si el usuario restaura un dispositivo y es posible que no estén presentes después de instalar una versión actualizada de la aplicación. Por ejemplo, en caso de que la aplicación no pueda conectarse a la red, puede usar el directorio Cachés para almacenar datos o archivos y proporcionar una buena experiencia sin conexión. La aplicación puede guardar y recuperar estos datos rápidamente mientras espera respuestas de red, pero no es necesario realizar copias de seguridad y se puede recuperar o volver a crear fácilmente después de una restauración o actualización de versión. |
tmp/ | Las aplicaciones pueden almacenar archivos temporales que solo son necesarios durante un breve período en este directorio. Para ahorrar espacio, los archivos deben eliminarse cuando ya no sean necesarios. El sistema operativo también puede eliminar archivos de este directorio cuando una aplicación no se está ejecutando. iTunes NO realiza una copia de seguridad del contenido de este directorio. Por ejemplo, en el directorio tmp se pueden almacenar archivos temporales que se descargan para mostrar al usuario (como avatares de Twitter o datos adjuntos de correo electrónico), pero que se podrían eliminar una vez que se hayan visto (y descargado de nuevo si son necesarios en el futuro). |
En esta captura de pantalla se muestra la estructura de directorios en una ventana de Finder:
Acceso a otros directorios mediante programación
En los ejemplos de archivos y directorios anteriores se ha accedido al directorio Documents
. Para escribir en otro directorio, debe construir una ruta de acceso mediante la sintaxis ".." como se muestra aquí:
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 creación de un directorio es similar:
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var library = Path.Combine (documents, "..", "Library");
var directoryname = Path.Combine (library, "NewLibraryDirectory");
Directory.CreateDirectory(directoryname);
Las rutas de acceso a los directorios Caches
y tmp
se pueden construir de la siguiente manera:
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var cache = Path.Combine (documents, "..", "Library", "Caches");
var tmp = Path.Combine (documents, "..", "tmp");
Uso compartido con la aplicación Files
iOS 11 introdujo la aplicación Files un explorador de archivos para iOS que permite al usuario ver e interactuar con sus archivos en iCloud y también con los almacenados por cualquier aplicación que lo admita. Para que el usuario pueda acceder directamente a los archivos de la aplicación, cree una nueva clave booleana en el archivo Info.plist LSSupportsOpeningDocumentsInPlace
y establézcalo en true
, como aquí:
El directorio Documentos de la aplicación ahora estará disponible para navegar en la aplicación Files. En la aplicación Files, vaya a On My iPhone (En mi iPhone) y podrá ver todas las aplicaciones con archivos compartidos. Las capturas de pantalla siguientes muestran el aspecto de la aplicación de ejemplo:
Uso compartido de archivos con el usuario a través de iTunes
Los usuarios pueden acceder a los archivos del directorio Documentos de la aplicación editando Info.plist
y creando una entrada aplicación que admita el uso compartido de iTunes (UIFileSharingEnabled
) en la vista Origen, como se muestra aquí:
Se puede acceder a estos archivos en iTunes cuando el dispositivo está conectado y el usuario elige la pestaña Apps
. Por ejemplo, en la captura de pantalla siguiente se muestran los archivos de la aplicación seleccionada compartida a través de iTunes:
Los usuarios solo pueden acceder a los elementos de nivel superior de este directorio a través de iTunes. No pueden ver el contenido de ningún subdirectorio (aunque pueden copiarlos en su equipo o eliminarlos). Por ejemplo, con GoodReader, PDF y EPUB los archivos se pueden compartir con la aplicación para que los usuarios puedan leerlos en sus dispositivos iOS.
Los usuarios que modifican el contenido de su carpeta Documentos pueden causar problemas si no son cuidadosos. La aplicación debe tener esto en cuenta y ser resistente a las actualizaciones destructivas de la carpeta Documentos.
El código de ejemplo de este artículo crea un archivo y una carpeta en la carpeta Documentos (en SampleCode.cs) y habilita el uso compartido de archivos en el archivo Info.plist. En esta captura de pantalla se muestra cómo aparecen en iTunes:
Consulte el artículo Trabajar con imágenes para obtener información sobre cómo establecer iconos para la aplicación y para cualquier tipo de documento personalizado que cree.
Si la clave UIFileSharingEnabled
es false o no está presente, el uso compartido de archivos está, de forma predeterminada, deshabilitado y los usuarios no podrán interactuar con el directorio Documentos.
Copia de seguridad y restauración
Cuando iTunes realiza una copia de seguridad de un dispositivo, todos los directorios creados en el directorio principal de la aplicación se guardarán excepto los directorios siguientes:
- [ApplicationName].app: no escriba en este directorio, ya que está firmado y, por tanto, debe permanecer sin cambios después de la instalación. Puede contener recursos a los que accede desde el código, pero no requieren copia de seguridad, ya que se restaurarían al volver a descargar la aplicación.
- Biblioteca/Cachés: el directorio de caché está pensado para los archivos de trabajo de los que no es necesario realizar una copia de seguridad.
- tmp: este directorio se usa para los archivos temporales que se crean y eliminan cuando ya no son necesarios, o para los archivos que iOS elimina cuando necesita espacio.
La copia de seguridad de una gran cantidad de datos puede tardar mucho tiempo. Si decide que necesita realizar una copia de seguridad de cualquier documento o datos concretos, la aplicación debe usar las carpetas Documentos y Biblioteca. En el caso de los datos o archivos transitorios que se pueden recuperar fácilmente de la red, use las memorias caché o el directorio tmp.
Nota:
iOS "limpiará" el sistema de archivos cuando el dispositivo se que quede con muy poco espacio en disco. Este proceso quitará todos los archivos de la carpeta Biblioteca/Cachés y tmp de las aplicaciones que no se están ejecutando actualmente.
Cumplimiento de las restricciones de copia de seguridad de iOS 5 iCloud
Nota:
Aunque esta directiva se introdujo por primera vez con iOS 5 (que parece hace mucho tiempo), la guía sigue siendo relevante para las aplicaciones en la actualidad.
Apple introdujo la funcionalidad de Copia de seguridad de iCloud con iOS 5. Cuando se habilita iCloud Backup, se realiza una copia de seguridad de todos los archivos del directorio principal de la aplicación (excepto los directorios de los que no se realiza una copia de seguridad normalmente, por ejemplo, la agrupación de aplicaciones, Caches
y tmp
) en los servidores de iCloud. Esta característica proporciona al usuario una copia de seguridad completa en caso de que su dispositivo se pierda, lo roben o se dañe.
Dado que iCloud solo proporciona 5 Gb de espacio libre a cada usuario y para evitar el uso innecesario del ancho de banda, Apple espera que las aplicaciones solo realicen copias de seguridad de los datos esenciales generados por el usuario. Para cumplir con las directrices de almacenamiento de datos de iOS, debe limitar la cantidad de datos de los que se realiza una copia de seguridad mediante la conformidad con los siguientes elementos:
- Almacene solo los datos generados por el usuario o los datos que no se puedan volver a crear en el directorio Documentos (del que se realiza una copia de seguridad).
- Almacene cualquier otro dato que pueda volver a crearse o a descargarse fácilmente en
Library/Caches
otmp
(del que no se realiza una copia de seguridad y podría "limpiarse"). - Si tiene archivos que podrían ser adecuados para la carpeta
Library/Caches
otmp
, pero no desea que se "limpien", almacénelos en otro lugar (comoLibrary/YourData
) y aplique el atributo "no hacer una copia de seguridad" para evitar que los archivos usen el ancho de banda de copia de seguridad de iCloud y el espacio de almacenamiento. Estos datos siguen usando espacio en el dispositivo, por lo que debe administrarlos cuidadosamente y eliminarlos siempre que sea posible.
El atributo "do not back up" se establece mediante la clase NSFileManager
. Asegúrese de que la clase es using Foundation
y llame a SetSkipBackupAttribute
de esta manera:
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
Cuando SetSkipBackupAttribute
sea true
, no se realizará una copia de seguridad del archivo, independientemente del directorio en el que se almacene (incluso en el directorio Documents
). Puede consultar el atributo mediante el método GetSkipBackupAttribute
y puede restablecerlo llamando al método SetSkipBackupAttribute
con false
, de la siguiente manera:
NSFileManager.SetSkipBackupAttribute (filename, false); // file will be backed-up
Uso compartido de datos entre aplicaciones iOS y extensiones de aplicaciones
Dado que las extensiones de aplicación se ejecutan como parte de una aplicación host (en lugar de su aplicación contenedora), el uso compartido de datos no se incluye automáticamente, por lo que se requiere trabajo adicional. Los grupos de aplicaciones son el mecanismo que iOS usa para permitir que diferentes aplicaciones compartan datos. Si las aplicaciones se han configurado correctamente con los derechos y el aprovisionamiento correctos, pueden acceder a un directorio compartido fuera de su espacio aislado normal de iOS.
Configurar un grupo de aplicaciones
La ubicación compartida se configura mediante un grupo de aplicaciones, que se configura en la sección Certificados, identificadores y perfiles del Centro para desarrolladores de iOS. También se debe hacer referencia a este valor en cada archivo Entitlements.plist del proyecto.
Para obtener información sobre cómo crear y configurar un grupo de aplicaciones, consulte la guía Capacidades de los grupos de aplicaciones.
Archivos
La aplicación iOS y la extensión también pueden compartir archivos mediante una ruta de acceso de archivo común (dado que se han configurado correctamente con los derechos y el aprovisionamiento correctos):
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
Si la ruta de acceso de grupo devuelta es null
, compruebe la configuración de los derechos y el perfil de aprovisionamiento y asegúrese de que son correctos.
Actualizaciones de la versión de la aplicación
Cuando se descarga una nueva versión de la aplicación, iOS crea un nuevo directorio principal y almacena la nueva agrupación de aplicaciones en ella. Después, iOS mueve las siguientes carpetas de la versión anterior de la agrupación de aplicaciones al nuevo directorio principal:
- Documentos
- Library
Otros directorios también se pueden copiar y colocar en el nuevo directorio principal, pero no se garantiza que se copien, por lo que la aplicación no debe depender de este comportamiento del sistema.
Resumen
En este artículo se mostró que las operaciones del sistema de archivos con Xamarin.iOS son similares a cualquier otra aplicación .NET. También introdujo el espacio aislado de la aplicación y examinó las implicaciones de seguridad que provoca. A continuación, ha explorado el concepto de una agrupación de aplicaciones. Por último, se enumeraron los directorios especializados disponibles para la aplicación y se explicaron sus roles durante las actualizaciones y copias de seguridad de la aplicación.