Compartilhar via


Armazenamento externo

O armazenamento externo refere-se ao armazenamento de arquivos que não está no armazenamento interno e não é exclusivamente acessível ao aplicativo responsável pelo arquivo. A principal finalidade do armazenamento externo é fornecer um local para colocar arquivos que devem ser compartilhados entre aplicativos ou que são muito grandes para caber no armazenamento interno.

Historicamente falando, o armazenamento externo se referia a uma partição de disco em mídia removível, como um cartão SD (também conhecido como armazenamento portátil). Essa distinção não é mais tão relevante quanto os dispositivos Android evoluíram e muitos dispositivos Android não dão mais suporte ao armazenamento removível. Em vez disso, alguns dispositivos alocarão parte de sua memória interna não volátil para Android, que pode executar a mesma função que a mídia removível. Isso é conhecido como armazenamento emulado e ainda é considerado armazenamento externo. Como alternativa, alguns dispositivos Android podem ter várias partições de armazenamento externas. Por exemplo, um tablet Android (além de seu armazenamento interno) pode ter armazenamento emulado e um ou mais slots para um cartão SD. Todas essas partições são tratadas pelo Android como armazenamento externo.

Em dispositivos que têm vários usuários, cada usuário terá um diretório dedicado na partição de armazenamento externa primária para seu armazenamento externo. Aplicativos em execução como um usuário não terão acesso a arquivos de outro usuário no dispositivo. Os arquivos para todos os usuários ainda são legíveis pelo mundo e podem ser gravados no mundo; no entanto, o Android irá área restrita de cada perfil de usuário dos outros.

A leitura e gravação em arquivos é quase idêntica no Xamarin.Android como em qualquer outro aplicativo .NET. O aplicativo Xamarin.Android determina o caminho para o arquivo que será manipulado e, em seguida, usa expressões padrão do .NET para acesso a arquivos. Como os caminhos reais para o armazenamento interno e externo podem variar de dispositivo para dispositivo ou da versão do Android para a versão do Android, não é recomendável codificar o caminho para os arquivos. Em vez disso, o Xamarin.Android expõe as APIs nativas do Android que ajudarão a determinar o caminho para arquivos no armazenamento interno e externo.

Este guia discutirá os conceitos e APIs no Android que são específicos do armazenamento externo.

Arquivos públicos e privados no armazenamento externo

Há dois tipos diferentes de arquivos que um aplicativo pode manter no armazenamento externo:

  • Arquivos privados – arquivos privados são arquivos específicos do seu aplicativo (mas ainda são legívels e graváveis no mundo). O Android espera que os arquivos privados sejam armazenados em um diretório específico no armazenamento externo. Embora os arquivos sejam chamados de "privados", eles ainda estão visíveis e acessíveis por outros aplicativos no dispositivo, eles não recebem nenhuma proteção especial pelo Android.

  • Arquivos públicos – são arquivos que não são considerados específicos do aplicativo e devem ser compartilhados livremente.

As diferenças entre esses arquivos são principalmente conceituais. Arquivos privados são privados no sentido de que eles são considerados como parte do aplicativo, enquanto arquivos públicos são quaisquer outros arquivos que existem no armazenamento externo. O Android fornece duas APIs diferentes para resolver os caminhos para arquivos públicos e privados, mas, caso contrário, as mesmas APIs do .NET são usadas para ler e gravar nesses arquivos. Essas são as mesmas APIs discutidas na seção sobre leitura e escrita.

Arquivos externos privados

Arquivos externos privados são considerados específicos de um aplicativo (semelhante a arquivos internos), mas estão sendo mantidos no armazenamento externo por vários motivos (como ser muito grande para armazenamento interno). Semelhante aos arquivos internos, esses arquivos serão excluídos quando o aplicativo for desinstalado pelo usuário.

O local primário para arquivos externos privados é encontrado chamando o método Android.Content.Context.GetExternalFilesDir(string type). Esse método retornará um Java.IO.File objeto que representa o diretório de armazenamento externo privado para o aplicativo. Passar null para esse método retornará o caminho para o diretório de armazenamento do usuário para o aplicativo. Por exemplo, para um aplicativo com o nome com.companyname.appdo pacote , o diretório "raiz" dos arquivos externos privados seria:

/storage/emulated/0/Android/data/com.companyname.app/files/

Este documento se referirá ao diretório de armazenamento para arquivos privados no armazenamento externo como PRIVATE_EXTERNAL_STORAGE.

O parâmetro para GetExternalFilesDir() é uma cadeia de caracteres que especifica um diretório de aplicativo. Esse é um diretório destinado a fornecer um local padrão para uma organização lógica de arquivos. Os valores de cadeia de caracteres estão disponíveis por meio de constantes na Android.OS.Environment classe :

Android.OS.Environment Diretório
DirectoryAlarms PRIVATE_EXTERNAL_STORAGE/Alarmes
DirectoryDcim PRIVATE_EXTERNAL_STORAGE/DCIM
DirectoryDownloads PRIVATE_EXTERNAL_STORAGE/Baixar
DirectoryDocuments PRIVATE_EXTERNAL_STORAGE/Documentos
DirectoryMovies PRIVATE_EXTERNAL_STORAGE/Filmes
DirectoryMusic PRIVATE_EXTERNAL_STORAGE/Música
DirectoryNotifications PRIVATE_EXTERNAL_STORAGE/Notificações
DirectoryPodcasts PRIVATE_EXTERNAL_STORAGE/Podcasts
DirectoryRingtones PRIVATE_EXTERNAL_STORAGE/Toques
DirectoryPictures PRIVATE_EXTERNAL_STORAGE/Imagens

Para dispositivos que têm várias partições de armazenamento externas, cada partição terá um diretório destinado a arquivos privados. O método Android.Content.Context.GetExternalFilesDirs(string type) retornará uma matriz de Java.IO.Files. Cada objeto representará um diretório específico do aplicativo privado em todos os dispositivos de armazenamento compartilhados/externos em que o aplicativo pode colocar os arquivos que possui.

Importante

O caminho exato para o diretório de armazenamento externo privado pode variar de dispositivo para dispositivo e entre versões do Android. Por isso, os aplicativos não devem codificar o caminho para esse diretório e, em vez disso, usar as APIs do Xamarin.Android, como Android.Content.Context.GetExternalFilesDir().

Arquivos externos públicos

Arquivos públicos são arquivos que existem no armazenamento externo que não são armazenados no diretório que o Android aloca para arquivos privados. Os arquivos públicos não serão excluídos quando o aplicativo for desinstalado. Os aplicativos Android devem receber permissão antes de poderem ler ou gravar arquivos públicos. É possível que os arquivos públicos existam em qualquer lugar no armazenamento externo, mas por convenção o Android espera que existam arquivos públicos no diretório identificado pela propriedade Android.OS.Environment.ExternalStorageDirectory. Essa propriedade retornará um Java.IO.File objeto que representa o diretório de armazenamento externo primário. Por exemplo, Android.OS.Environment.ExternalStorageDirectory pode se referir ao seguinte diretório:

/storage/emulated/0/

Este documento se referirá ao diretório de armazenamento para arquivos públicos no armazenamento externo como PUBLIC_EXTERNAL_STORAGE.

O Android também dá suporte ao conceito de diretórios de aplicativos em PUBLIC_EXTERNAL_STORAGE. Esses diretórios são exatamente os mesmos que os diretórios do aplicativo para PRIVATE_EXTERNAL_STORAGE e são descritos na tabela na seção anterior. O método Android.OS.Environment.GetExternalStoragePublicDirectory(string directoryType) retornará um Java.IO.File objeto que corresponde a um diretório de aplicativo público. O directoryType parâmetro é um parâmetro obrigatório e não pode ser null.

Por exemplo, chamar Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDocuments).AbsolutePath retornará uma cadeia de caracteres que será semelhante a:

/storage/emulated/0/Documents

Importante

O caminho exato para o diretório de armazenamento externo público pode variar de dispositivo para dispositivo e entre versões do Android. Por isso, os aplicativos não devem codificar o caminho para esse diretório e, em vez disso, usar as APIs do Xamarin.Android, como Android.OS.Environment.ExternalStorageDirectory.

Trabalhando com armazenamento externo

Depois que um aplicativo Xamarin.Android tiver obtido o caminho completo para um arquivo, ele deverá utilizar qualquer uma das APIs padrão do .NET para criar, ler, gravar ou excluir arquivos. Isso maximiza a quantidade de código compatível entre plataformas para um aplicativo. No entanto, antes de tentar acessar um arquivo, um aplicativo Xamarin.Android deve garantir que seja possível acessar esse arquivo.

  1. Verificar o armazenamento externo – dependendo da natureza do armazenamento externo, é possível que ele não seja montado e utilizável pelo aplicativo. Todos os aplicativos devem marcar o estado do armazenamento externo antes de tentar usá-lo.
  2. Executar uma permissão de runtime marcar – um aplicativo Android deve solicitar permissão do usuário para acessar o armazenamento externo. Isso significa que uma solicitação de permissão de tempo de execução deve ser executada antes de qualquer acesso ao arquivo. O guia Permissões no Xamarin.Android contém mais detalhes sobre permissões do Android.

Cada uma dessas duas tarefas será discutida abaixo.

Verificando se o armazenamento externo está disponível

A primeira etapa antes de gravar no armazenamento externo é marcar que ele é legível ou gravável. A Android.OS.Environment.ExternalStorageState propriedade contém uma cadeia de caracteres que identifica o estado do armazenamento externo. Essa propriedade retornará uma cadeia de caracteres que representa o estado. Esta tabela é uma lista dos ExternalStorageState valores que podem ser retornados por Environment.ExternalStorageState:

ExternalStorageState Descrição
MediaBadRemoval A mídia foi abruptamente removida sem ser desmontada corretamente.
MediaChecking A mídia está presente, mas passando por uma marcar de disco.
MediaEjecting A mídia está em processo de desmontagem e ejetação.
MediaMounted A mídia é montada e pode ser lida ou gravada.
MediaMountedReadOnly A mídia é montada, mas só pode ser lida.
MediaNofs A mídia está presente, mas não contém um sistema de arquivos adequado para Android.
MediaRemoved Não há mídia presente.
MediaShared A mídia está presente, mas não está montada. Ele está sendo compartilhado via USB com outro dispositivo.
MediaUnknown O estado da mídia não é reconhecido pelo Android.
MediaUnmountable A mídia está presente, mas não pode ser montada pelo Android.
MediaUnmounted A mídia está presente, mas não está montada.

A maioria dos aplicativos Android só precisará marcar se o armazenamento externo estiver montado. O snippet de código a seguir mostra como verificar se o armazenamento externo está montado para acesso somente leitura ou acesso de leitura/gravação:

bool isReadonly = Environment.MediaMountedReadOnly.Equals(Environment.ExternalStorageState);
bool isWriteable = Environment.MediaMounted.Equals(Environment.ExternalStorageState);

Permissões de armazenamento externo

O Android considera o acesso ao armazenamento externo uma permissão perigosa, o que normalmente exige que o usuário conceda permissão para acessar o recurso. O usuário pode revogar essa permissão a qualquer momento. Isso significa que uma solicitação de permissão de tempo de execução deve ser executada antes de qualquer acesso ao arquivo. Os aplicativos recebem automaticamente permissões para ler e gravar seus próprios arquivos privados. É possível que os aplicativos leiam e escrevam os arquivos privados que pertencem a outros aplicativos depois de receberem permissão do usuário.

Todos os aplicativos Android devem declarar uma das duas permissões para armazenamento externo no AndroidManifest.xml . Para identificar as permissões, um dos dois uses-permission elementos a seguir deve ser adicionado ao AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Observação

Se o usuário conceder WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE também será concedido implicitamente. Não é necessário solicitar ambas as permissões no AndroidManifest.xml.

As permissões também podem ser adicionadas usando a guia Manifesto do Android das propriedades da solução:

Gerenciador de Soluções – Permissões necessárias para o Visual Studio

Em geral, todas as permissões perigosas devem ser aprovadas pelo usuário. As permissões para armazenamento externo são uma anomalia, pois há exceções a essa regra, dependendo da versão do Android em que o aplicativo está em execução:

Fluxograma de verificações de permissão de armazenamento externo

Para obter mais informações sobre como executar solicitações de permissão de runtime, consulte o guia Permissões no Xamarin.Android. O LocalFilesde exemplo monodróide também demonstra uma maneira de executar verificações de permissão de runtime.

Concedendo e revogando permissões com o ADB

No curso do desenvolvimento de um aplicativo Android, pode ser necessário conceder e revogar permissões para testar os vários fluxos de trabalho envolvidos com verificações de permissão de runtime. É possível fazer isso no prompt de comando usando o ADB. Os snippets de linha de comando a seguir demonstram como conceder ou revogar permissões usando o ADB para um aplicativo Android cujo nome de pacote é com.companyname.app:

$ adb shell pm grant com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE

$ adb shell pm revoke com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE

Excluindo arquivos

Qualquer uma das APIs padrão do C# pode ser usada para excluir um arquivo do armazenamento externo, como System.IO.File.Delete. Também é possível usar as APIs Java em detrimento da portabilidade do código. Por exemplo:

System.IO.File.Delete("/storage/emulated/0/Android/data/com.companyname.app/files/count.txt");