Partilhar via


Acesso ao sistema de arquivos no Xamarin.iOS

Você pode usar o Xamarin.iOS e as System.IOclasses na BCL (Biblioteca de Classes Base) do .NET para acessar o sistema de arquivos iOS. A classe File permite criar, excluir e ler arquivos e a classe Directory permite criar, excluir ou enumerar o conteúdo de diretórios. Você também pode usar Stream subclasses, que podem fornecer um maior grau de controle sobre as operações de arquivo (como compactação ou pesquisa de posição em um arquivo).

O iOS impõe algumas restrições sobre o que um aplicativo pode fazer com o sistema de arquivos para preservar a segurança dos dados de um aplicativo e proteger os usuários de aplicativos malignos. Essas restrições fazem parte do Application Sandbox – um conjunto de regras que limita o acesso de um aplicativo a arquivos, preferências, recursos de rede, hardware, etc. Um aplicativo é limitado a ler e gravar arquivos dentro de seu diretório pessoal (local instalado); ele não pode acessar os arquivos de outro aplicativo.

O iOS também tem alguns recursos específicos do sistema de arquivos: certos diretórios exigem tratamento especial em relação a backups e atualizações, e os aplicativos também podem compartilhar arquivos entre si e com o aplicativo Arquivos (desde o iOS 11) e via iTunes.

Este artigo discute os recursos e restrições do sistema de arquivos iOS e inclui um aplicativo de exemplo que demonstra como usar o Xamarin.iOS para executar algumas operações simples do sistema de arquivos:

Uma amostra do iOS executando algumas operações simples do sistema de arquivos

Acesso geral a arquivos

Xamarin.iOS permite que você use as classes .NET System.IO para operações do sistema de arquivos no iOS.

Os trechos de código a seguir ilustram algumas operações de arquivo comuns. Você encontrará todos eles abaixo no arquivo SampleCode.cs, no aplicativo de exemplo para este artigo.

Trabalhar com diretórios

Esse código enumera os subdiretórios no diretório atual (especificado pelo parâmetro "./"), que é o local do executável do aplicativo. Sua saída será uma lista de todos os arquivos e pastas que são implantados com seu aplicativo (exibido na janela do console enquanto você está depurando).

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

Lendo arquivos

Para ler um arquivo de texto, você só precisa de uma única linha de código. Este exemplo exibirá o conteúdo de um arquivo de texto na janela Saída do aplicativo.

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

Serialização XML

Embora trabalhar com o namespace completo System.Xml esteja além do escopo deste artigo, você pode facilmente desserializar um documento XML do sistema de arquivos usando um StreamReader como este trecho de código:

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

Para obter mais informações, consulte a documentação de System.Xml e serialização. Consulte a documentação do Xamarin.iOS no vinculador – geralmente você precisará adicionar o [Preserve] atributo às classes que pretende serializar.

Criando arquivos e diretórios

Este exemplo mostra como usar a Environment classe para acessar a pasta Documentos onde podemos criar arquivos e diretórios.

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

Criar um diretório é um processo semelhante:

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

Para obter mais informações, consulte a referência da API System.IO.

Serializando JSON

Json.NET é uma estrutura JSON de alto desempenho que funciona com o Xamarin.iOS e está disponível no NuGet. Adicione o pacote NuGet ao seu projeto de aplicativo, usando Adicionar NuGet no Visual Studio para Mac:

Adicionando o pacote NuGet ao projeto de aplicativos

Em seguida, adicione uma classe para atuar como o modelo de dados para serialização/desserialização (neste 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() {
        }
    }
}

Finalmente, crie uma instância da classe, serialize-a Account em dados json e grave-a em um arquivo:

// 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 obter mais informações sobre como trabalhar com dados json em um aplicativo .NET, consulte a documentação do Json.NET.

Considerações especiais

Apesar das semelhanças entre as operações de arquivo Xamarin.iOS e .NET, o iOS e o Xamarin.iOS diferem do .NET de algumas maneiras importantes.

Tornando os arquivos de projeto acessíveis em tempo de execução

Por padrão, se você adicionar um arquivo ao seu projeto, ele não será incluído no assembly final e, portanto, não estará disponível para seu aplicativo. Para incluir um arquivo no assembly, você deve marcá-lo com uma ação de compilação especial, chamada Content.

Para marcar um arquivo para inclusão, clique com o botão direito do mouse no(s) arquivo(s) e escolha Criar conteúdo de ação > no Visual Studio para Mac. Você também pode alterar a Ação de Criação na folha Propriedades do arquivo.

Diferenciar maiúsculas de minúsculas

É importante entender que o sistema de arquivos iOS diferencia maiúsculas de minúsculas. A diferenciação de maiúsculas e minúsculas significa que os nomes de arquivo e diretório devem corresponder exatamente – README.txt e readme.txt seriam considerados nomes de arquivos diferentes.

Isso pode ser confuso para desenvolvedores .NET que estão mais familiarizados com o sistema de arquivos do Windows, que não diferencia maiúsculas de minúsculasArquivos, Arquivos e arquivos se referem ao mesmo diretório.

Aviso

O simulador do iOS NÃO diferencia maiúsculas de minúsculas. Se a caixa do nome do arquivo for diferente entre o arquivo em si e as referências a ele no código, seu código ainda poderá funcionar no simulador, mas falhará em um dispositivo real. Essa é uma das razões pelas quais é importante implantar e testar em um dispositivo real no início e, muitas vezes, durante o desenvolvimento do iOS.

Separador de caminho

O iOS usa a barra '/'como separador de caminho (que é diferente do Windows, que usa a barra invertida '\').

Devido a essa diferença confusa, é uma boa prática usar o System.IO.Path.Combine método, que se ajusta para a plataforma atual, em vez de codificar um separador de caminho específico. Este é um passo simples que torna seu código mais portátil para outras plataformas.

Área restrita do aplicativo

O acesso do aplicativo ao sistema de arquivos (e a outros recursos, como os recursos de rede e hardware) é limitado por motivos de segurança. Essa restrição é conhecida como Application Sandbox. Em termos de sistema de arquivos, seu aplicativo está limitado a criar e excluir arquivos e diretórios em seu diretório base.

O diretório base é um local exclusivo no sistema de arquivos onde seu aplicativo e todos os seus dados são armazenados. Você não pode escolher (ou alterar) o local do diretório base do seu aplicativo; no entanto, iOS e Xamarin.iOS fornecem propriedades e métodos para gerenciar os arquivos e diretórios dentro.

O pacote de aplicativos

O pacote de aplicativos é a pasta que contém seu aplicativo. Ele se distingue de outras pastas por ter o sufixo .app adicionado ao nome do diretório. Seu pacote de aplicativos contém seu arquivo executável e todo o conteúdo (arquivos, imagens, etc.) necessário para o seu projeto.

Quando você navega para o pacote de aplicativos no Mac OS, ele aparece com um ícone diferente do que você vê em outros diretórios (e o sufixo .app está oculto), no entanto, é apenas um diretório regular que o sistema operacional está exibindo de forma diferente.

Para exibir o pacote de aplicativos para o código de exemplo, clique com o botão direito do mouse no projeto no Visual Studio para Mac e selecione Revelar no Finder. Em seguida, navegue até o diretório bin/ , onde você deve encontrar um ícone de aplicativo (semelhante à captura de tela abaixo).

Navegue pelo diretório bin para encontrar um ícone de aplicativo semelhante a esta captura de tela

Clique com o botão direito do mouse nesse ícone e escolha Mostrar conteúdo do pacote para procurar o conteúdo do diretório do pacote de aplicativos. O conteúdo aparece exatamente como o conteúdo de um diretório regular, como mostrado aqui:

O conteúdo do pacote de aplicativos

O pacote de aplicativos é o que é instalado no simulador ou no seu dispositivo durante o teste e, em última análise, é o que é enviado à Apple para inclusão na App Store.

Diretórios de aplicativos

Quando o aplicativo é instalado em um dispositivo, o sistema operacional cria um diretório base para seu aplicativo e cria vários diretórios dentro do diretório raiz do aplicativo que estão disponíveis para uso. Desde o iOS 8, os diretórios acessíveis pelo usuário NÃO estão localizados na raiz do aplicativo, portanto, você não pode derivar os caminhos para o pacote de aplicativos dos diretórios do usuário, ou vice-versa.

Esses diretórios, como determinar seu caminho e suas finalidades estão listados abaixo:

 

Diretório Descrição
[Nome do Aplicativo].app/ No iOS 7 e versões anteriores, este é o diretório onde o ApplicationBundle executável do aplicativo está armazenado. A estrutura de diretório que você cria em seu aplicativo existe nesse diretório (por exemplo, imagens e outros tipos de arquivo que você marcou como Recursos em seu projeto do Visual Studio para Mac).

Se você precisar acessar os arquivos de conteúdo dentro do pacote de aplicativos, o caminho para esse diretório estará disponível por meio da NSBundle.MainBundle.BundlePath propriedade.
Documentos/ Use esse diretório para armazenar documentos do usuário e arquivos de dados do aplicativo.

O conteúdo deste diretório pode ser disponibilizado para o usuário através do compartilhamento de arquivos do iTunes (embora isso esteja desativado por padrão). Adicione uma UIFileSharingEnabled chave booleana ao arquivo Info.plist para permitir que os usuários acessem esses arquivos.

Mesmo que um aplicativo não habilite imediatamente o compartilhamento de arquivos, você deve evitar colocar arquivos que devem ser ocultos dos usuários nesse diretório (como arquivos de banco de dados, a menos que você pretenda compartilhá-los). Enquanto os arquivos confidenciais permanecerem ocultos, esses arquivos não serão expostos (e potencialmente movidos, modificados ou excluídos pelo iTunes) se o compartilhamento de arquivos estiver habilitado em uma versão futura.

Você pode usar o Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) método para obter o caminho para o diretório Documents para seu aplicativo.

O conteúdo deste diretório é feito backup pelo iTunes.
Biblioteca/ O diretório Biblioteca é um bom lugar para armazenar arquivos que não são criados diretamente pelo usuário, como bancos de dados ou outros arquivos gerados pelo aplicativo. O conteúdo deste diretório nunca é exposto ao usuário via iTunes.

Você pode criar seus próprios subdiretórios na Biblioteca; no entanto, já existem alguns diretórios criados pelo sistema aqui que você deve estar ciente, incluindo Preferências e Caches.

O conteúdo desse diretório (exceto o subdiretório Caches) é copiado pelo iTunes. Será feito backup dos diretórios personalizados criados na Biblioteca.
Biblioteca/Preferências/ Os arquivos de preferência específicos do aplicativo são armazenados nesse diretório. Não crie esses arquivos diretamente. Em vez disso, use a NSUserDefaults classe.

O conteúdo deste diretório é feito backup pelo iTunes.
Biblioteca/Caches/ O diretório Caches é um bom lugar para armazenar arquivos de dados que podem ajudar seu aplicativo a ser executado, mas que podem ser facilmente recriados. O aplicativo deve criar e excluir esses arquivos conforme necessário e ser capaz de recriar esses arquivos, se necessário. O iOS 5 também pode excluir esses arquivos (em situações de baixo armazenamento), no entanto, não o fará enquanto o aplicativo estiver em execução.

O conteúdo desse diretório NÃO é copiado pelo iTunes, o que significa que eles não estarão presentes se o usuário restaurar um dispositivo e podem não estar presentes depois que uma versão atualizada do seu aplicativo for instalada.

Por exemplo, caso seu aplicativo não possa se conectar à rede, você pode usar o diretório Caches para armazenar dados ou arquivos para fornecer uma boa experiência offline. O aplicativo pode salvar e recuperar esses dados rapidamente enquanto aguarda as respostas da rede, mas não precisa de backup e pode ser facilmente recuperado ou recriado após uma restauração ou atualização de versão.
Tmp/ Os aplicativos podem armazenar arquivos temporários que são necessários apenas por um curto período neste diretório. Para economizar espaço, os arquivos devem ser excluídos quando não forem mais necessários. O sistema operacional também pode excluir arquivos desse diretório quando um aplicativo não está em execução.

O conteúdo deste diretório NÃO é copiado pelo iTunes.

Por exemplo, o diretório tmp pode ser usado para armazenar arquivos temporários que são baixados para exibição para o usuário (como avatares do Twitter ou anexos de e-mail), mas que podem ser excluídos depois de visualizados (e baixados novamente se forem necessários no futuro).

Esta captura de tela mostra a estrutura de diretórios em uma janela do Finder:

Esta captura de tela mostra a estrutura de diretórios em uma janela do Finder

Acessando outros diretórios programaticamente

Os exemplos de diretório e arquivo anteriores acessaram o Documents diretório. Para gravar em outro diretório, você deve construir um caminho usando a sintaxe ".." como mostrado aqui:

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");

A criação de um diretório é semelhante:

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

Os caminhos para os Caches diretórios e tmp podem ser construídos assim:

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

Compartilhamento com o aplicativo Arquivos

O iOS 11 introduziu o aplicativo Files - um navegador de arquivos para iOS que permite ao usuário ver e interagir com seus arquivos no iCloud e também armazenados por qualquer aplicativo que o suporte. Para permitir que o usuário acesse diretamente os arquivos em seu aplicativo, crie uma nova chave booleana no arquivo LSSupportsOpeningDocumentsInPlace Info.plist e defina-a como true, como aqui:

Definir LSSupportsOpeningDocumentsInPlace em Info.plist

O diretório Documentos do aplicativo agora estará disponível para navegação no aplicativo Arquivos. No aplicativo Arquivos, navegue até No Meu iPhone e cada aplicativo com arquivos compartilhados ficará visível. As capturas de tela abaixo mostram a aparência do aplicativo de exemplo:

Aplicativo Arquivos do iOS 11Procurar meus arquivos do iPhoneArquivos de aplicativo de exemplo

Partilhar ficheiros com o utilizador através do iTunes

Os usuários podem acessar os arquivos no diretório Documentos do seu aplicativo editando Info.plist e criando um Aplicativo que suporte a entrada de compartilhamento (UIFileSharingEnabled) do iTunes na visualização Código-fonte , conforme mostrado aqui:

Adicionar o aplicativo suporta a propriedade de compartilhamento do iTunes

Esses arquivos podem ser acessados no iTunes quando o dispositivo está conectado e o usuário escolhe a Apps guia. Por exemplo, a captura de tela a seguir mostra os arquivos no aplicativo selecionado compartilhados via iTunes:

Esta captura de tela mostra os arquivos no aplicativo selecionado compartilhados via iTunes

Os usuários só podem acessar os itens de nível superior neste diretório via iTunes. Eles não podem ver o conteúdo de nenhum subdiretório (embora possam copiá-los para o computador ou excluí-los). Por exemplo, com o GoodReader, arquivos PDF e EPUB podem ser compartilhados com o aplicativo para que os usuários possam lê-los em seus dispositivos iOS.

Os usuários que modificam o conteúdo da pasta Documentos podem causar problemas se não forem cuidadosos. Seu aplicativo deve levar isso em consideração e ser resiliente a atualizações destrutivas da pasta Documentos.

O código de exemplo para este artigo cria um arquivo e uma pasta na pasta Documentos (em SampleCode.cs) e habilita o compartilhamento de arquivos no arquivo Info.plist. Esta captura de tela mostra como eles aparecem no iTunes:

Esta captura de tela mostra como os arquivos aparecem no iTunes

Consulte o artigo Trabalhando com imagens para obter informações sobre como definir ícones para o aplicativo e para qualquer tipo de documento personalizado criado.

Se a UIFileSharingEnabled chave for false ou não estiver presente, o compartilhamento de arquivos será, por padrão, desabilitado e os usuários não poderão interagir com o diretório Documentos.

Backup e restauração

Quando um dispositivo é copiado pelo iTunes, todos os diretórios criados no diretório pessoal do aplicativo serão salvos, exceto os seguintes diretórios:

  • [ApplicationName].app – Não escreva neste diretório, pois ele está assinado e, portanto, deve permanecer inalterado após a instalação. Ele pode conter recursos que você acessa a partir do seu código, mas eles não exigem backup, pois seriam restaurados baixando novamente o aplicativo.
  • Biblioteca/Caches – O diretório de cache destina-se a arquivos de trabalho que não precisam de backup.
  • tmp – Esse diretório é usado para arquivos temporários que são criados e excluídos quando não são mais necessários, ou para arquivos que o iOS exclui quando precisa de espaço.

Fazer backup de uma grande quantidade de dados pode levar muito tempo. Se você decidir que precisa fazer backup de qualquer documento ou dados específicos, seu aplicativo deve usar as pastas Documentos e Biblioteca. Para dados transitórios ou arquivos que podem ser facilmente recuperados da rede, use os Caches ou o diretório tmp.

Observação

O iOS "limpará" o sistema de arquivos quando um dispositivo estiver criticamente com pouco espaço em disco. Esse processo removerá todos os arquivos da Biblioteca/Caches e da pasta tmp dos aplicativos que não estão em execução no momento.

Conformidade com as restrições de backup do iOS 5 iCloud

Observação

Embora essa política tenha sido introduzida pela primeira vez com o iOS 5 (o que parece ter sido há muito tempo), a orientação ainda é relevante para os aplicativos de hoje.

A Apple introduziu a funcionalidade de Backup do iCloud com o iOS 5. Quando o Backup do iCloud está ativado, todos os arquivos no diretório base do aplicativo (excluindo diretórios que normalmente não são copiados, por exemplo, o pacote de Cachesaplicativos e tmp) são copiados para os servidores do iCloud. Esse recurso fornece ao usuário um backup completo caso seu dispositivo seja perdido, roubado ou danificado.

Como o iCloud fornece apenas 5 Gb de espaço livre para cada usuário e para evitar o uso desnecessário de largura de banda, a Apple espera que os aplicativos façam backup apenas de dados essenciais gerados pelo usuário. Para estar em conformidade com as Diretrizes de Armazenamento de Dados do iOS, você deve limitar a quantidade de dados cujo backup é feito aderindo aos seguintes itens:

  • Armazene apenas dados gerados pelo usuário, ou dados que não possam ser recriados, no diretório Documentos (do qual é feito backup).
  • Armazene quaisquer outros dados que possam ser facilmente recriados ou baixados novamente em Library/Caches ou tmp (que não tenham backup e possam ser "limpos").
  • Se você tiver arquivos que podem ser apropriados para a Library/Caches pasta ou tmp mas não quiser ser "limpo", armazene-os em outro lugar (como Library/YourData) e aplique o atributo 'não fazer backup' para evitar que os arquivos usem a largura de banda e o espaço de armazenamento do Backup do iCloud. Esses dados ainda consomem espaço no dispositivo, então você deve gerenciá-los cuidadosamente e excluí-los quando possível.

O atributo 'do not back up' é definido usando a NSFileManager classe. Certifique-se de que sua turma está using Foundation e ligue SetSkipBackupAttribute assim:

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 é true que o arquivo não será copiado, independentemente do diretório em que ele está armazenado (mesmo o Documents diretório). Você pode consultar o atributo usando o GetSkipBackupAttribute método e pode redefini-lo chamando o SetSkipBackupAttribute método com false, da seguinte forma:

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

Compartilhando dados entre aplicativos iOS e extensões de aplicativo

Como as Extensões de Aplicativo são executadas como parte de um aplicativo host (em oposição ao aplicativo que as contém), o compartilhamento de dados não é incluído automaticamente, portanto, é necessário trabalho extra. Os Grupos de Aplicativos são o mecanismo que o iOS usa para permitir que diferentes aplicativos compartilhem dados. Se os aplicativos tiverem sido configurados corretamente com os direitos e provisionamento corretos, eles poderão acessar um diretório compartilhado fora de sua área restrita normal do iOS.

Configurar um grupo de aplicativos

O local compartilhado é configurado usando um Grupo de Aplicativos, que é configurado na seção Certificados, Identificadores e Perfis no Centro de Desenvolvimento do iOS. Esse valor também deve ser referenciado no Entitlements.plist de cada projeto.

Para obter informações sobre como criar e configurar um Grupo de Aplicativos, consulte o Guia de Recursos do Grupo de Aplicativos .

Arquivos

O aplicativo iOS e a extensão também podem compartilhar arquivos usando um caminho de arquivo comum (desde que tenham sido configurados corretamente com os direitos e provisionamento corretos):

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 o Caminho do Grupo retornado for null, verifique a configuração dos direitos e o perfil de provisionamento e verifique se eles estão corretos.

Atualizações de versão do aplicativo

Quando uma nova versão do seu aplicativo é baixada, o iOS cria um novo diretório base e armazena o novo pacote de aplicativos nele. Em seguida, o iOS move as seguintes pastas da versão anterior do pacote de aplicativos para o novo diretório base:

  • Documentos
  • Biblioteca

Outros diretórios também podem ser copiados e colocados em seu novo diretório base, mas não é garantido que sejam copiados, portanto, seu aplicativo não deve depender desse comportamento do sistema.

Resumo

Este artigo mostrou que as operações do sistema de arquivos com Xamarin.iOS são semelhantes a qualquer outro aplicativo .NET. Ele também introduziu o Application Sandbox e examinou as implicações de segurança que ele causa. Em seguida, explorou o conceito de um pacote de aplicativos. Finalmente, ele enumerou os diretórios especializados disponíveis para seu aplicativo e explicou suas funções durante atualizações e backups de aplicativos.