Para dar aos usuários mais controle sobre os arquivos e limitar a desorganização dos arquivos, o Android 10 introduziu um novo modelo de armazenamento para apps chamado armazenamento com escopo. O armazenamento com escopo muda a forma como os apps armazenam e acessam arquivos no armazenamento externo de um dispositivo. Para migrar seu app para oferecer suporte ao armazenamento com escopo, siga as práticas recomendadas para casos de uso de armazenamento comuns descritas neste guia. Os casos de uso são organizados em duas categorias: gerenciamento de arquivos de mídia e gerenciamento de arquivos que não são de mídia.
Para saber mais sobre como armazenar e acessar arquivos no Android, consulte os guias de treinamento de armazenamento.
Gerenciar arquivos de mídia
Esta seção descreve alguns dos casos de uso comuns para lidar com arquivos de mídia (arquivos de vídeo, imagem e áudio) e explica a abordagem de alto nível que seu app pode usar. A tabela a seguir resume cada um desses casos de uso e links para cada uma das seções que contêm mais detalhes.
Caso de uso | Resumo |
---|---|
Mostrar todos os arquivos de imagem ou vídeo | Use a mesma abordagem para todas as versões do Android. |
Mostrar imagens ou vídeos de uma pasta específica | Use a mesma abordagem para todas as versões do Android. |
Acessar informações de localização de fotos | Use uma abordagem se o app usar armazenamento com escopo. Use uma abordagem diferente se o app desativar o armazenamento com escopo. |
Definir o local de armazenamento para novos downloads | Use uma abordagem se o app usar armazenamento com escopo. Use uma abordagem diferente se o app desativar o armazenamento com escopo. |
Exportar arquivos de mídia do usuário para um dispositivo | Use a mesma abordagem para todas as versões do Android. |
Modificar ou excluir vários arquivos de mídia em uma única operação | Use uma abordagem para o Android 11. Para o Android 10, desative o armazenamento com escopo e use a abordagem para o Android 9 e versões anteriores. |
Importar uma única imagem que já existe | Use a mesma abordagem para todas as versões do Android. |
Capturar uma única imagem | Use a mesma abordagem para todas as versões do Android. |
Compartilhar arquivos de mídia com outros apps | Use a mesma abordagem para todas as versões do Android. |
Compartilhar arquivos de mídia com um app específico | Use a mesma abordagem para todas as versões do Android. |
Acessar arquivos de código ou bibliotecas que usam caminhos de arquivo diretos | Use uma abordagem para o Android 11. Para o Android 10, desative o armazenamento com escopo e use a abordagem para o Android 9 e versões anteriores. |
Mostrar arquivos de imagem ou vídeo de várias pastas
Consulte uma coleção de mídia
usando a API
query()
. Para filtrar ou classificar os arquivos de mídia, ajuste os parâmetros projection
, selection
, selectionArgs
e sortOrder
.
Mostrar imagens ou vídeos de uma pasta específica
Use esta abordagem:
- Seguindo as práticas recomendadas descritas em Solicitar permissões do app,
solicite a permissão
READ_EXTERNAL_STORAGE
. - Extraia arquivos de mídia com base no valor de
MediaColumns.DATA
, que contém o caminho absoluto do sistema de arquivos para o item de mídia no disco.
Observação: ao acessar um arquivo de mídia existente, você pode usar o valor
da coluna DATA
na sua lógica. Isso ocorre porque esse valor tem um caminho de arquivo válido.
No entanto, não presuma que o arquivo vai estar sempre disponível. Esteja preparado para processar
todos os erros de E/S causados por arquivo que possam ocorrer.
Por outro lado, para criar ou atualizar um arquivo de mídia, não use a coluna
DATA
. Em vez disso, use as colunas DISPLAY_NAME
e
RELATIVE_PATH
.
Acessar informações de local de fotos
Se o app usa o armazenamento com escopo, siga as etapas na seção Informações de localização em fotografias do guia de armazenamento de mídia.
Definir o local de armazenamento para novos downloads
Se o app usa armazenamento com escopo, preste atenção ao local escolhido para armazenar os arquivos de mídia transferidos por download.
Caso outros apps precisam acessar os arquivos, use coleções de mídia bem definidas para coleções de downloads ou de documentos.
No Android 11 e versões mais recentes, os arquivos no diretório externo
específico do app não podem ser acessados por outros apps, mesmo que você use DownloadManager
para
buscar esses arquivos.
Exportar arquivos de mídia do usuário para um dispositivo
Defina um local padrão apropriado para armazenar arquivos de mídia do usuário:
- Permita que os usuários escolham se querem permitir que os arquivos de mídia sejam lidos por outros apps, usando armazenamento específico do app ou armazenamento compartilhado.
- Permitir que os usuários exportem arquivos de diretórios específicos do app para um local mais acessível. Use coleções de imagens, vídeos e áudios da MediaStore para exportar arquivos de mídia para a galeria do dispositivo.
Modificar ou excluir vários arquivos de mídia em uma única operação
Incorpore a lógica com base nas versões do Android em que seu app é executado.
Em execução no Android 11
Use esta abordagem:
- Crie uma intent pendente para a solicitação de gravação ou exclusão do app usando
MediaStore.createWriteRequest()
ouMediaStore.createTrashRequest()
e solicite permissão do usuário para editar um conjunto de arquivos invocando essa intent. Avalie a resposta do usuário:
- Se a permissão foi concedida, prossiga com a operação de modificação ou exclusão.
- Se a permissão não foi concedida, explique ao usuário por que o recurso do app precisa da permissão.
Saiba mais sobre como gerenciar grupos de arquivos de mídia usando esses métodos, disponíveis no Android 11 e em versões mais recentes.
Em execução no Android 10
Se o app for destinado ao Android 10 (nível 29 da API), desative o armazenamento com escopo e continue usando a abordagem do Android 9 e versões anteriores para realizar essa operação.
Em execução no Android 9 ou versões anteriores
Use esta abordagem:
- Seguindo as práticas recomendadas descritas em Solicitar permissões do app,
solicite a permissão
WRITE_EXTERNAL_STORAGE
. - Use a API
MediaStore
para modificar ou excluir os arquivos de mídia.
Importar uma única imagem que já existe
Quando você quer importar uma única imagem que já existe (por exemplo, para usar como foto no perfil de um usuário), seu app poderá usar a própria IU para a operação ou o seletor do sistema.
Apresentar sua própria interface do usuário
Use esta abordagem:
- Seguindo as práticas recomendadas descritas em Solicitar permissões do app,
solicite a permissão
READ_EXTERNAL_STORAGE
. - Use a API
query()
para consultar uma coleção de mídia. - Exiba os resultados na IU personalizada do seu app.
Usar o seletor de sistema
Use a intent ACTION_GET_CONTENT
,
que solicita que o usuário escolha uma imagem para importar.
Se você quiser filtrar os tipos de imagens que o seletor de sistema apresenta ao
usuário, use
setType()
ou EXTRA_MIME_TYPES
.
Capturar uma única imagem
Quando você quiser capturar uma única imagem que vai ser usada no app (por exemplo, para ser a
foto do perfil de um usuário), use a intent
ACTION_IMAGE_CAPTURE
e peça ao usuário para tirar uma foto usando a câmera do dispositivo. O sistema armazena a foto capturada na tabela MediaStore.Images
.
Compartilhar arquivos de mídia com outros apps
Use o método
insert()
para adicionar registros diretamente ao MediaStore. Para mais informações, consulte a seção Adicionar um item do guia de armazenamento de mídia.
Compartilhar arquivos de mídia com um app específico
Use o componente FileProvider
do Android, conforme descrito no guia Como configurar o compartilhamento
de arquivos.
Acessar arquivos de código ou bibliotecas que usam caminhos de arquivo diretos
Incorpore a lógica com base nas versões do Android em que seu app é executado.
Em execução no Android 11
Use esta abordagem:
- Seguindo as práticas recomendadas descritas em Solicitar permissões do app,
solicite a permissão
READ_EXTERNAL_STORAGE
. - Acesse os arquivos usando caminhos de arquivo diretos.
Para saber mais, consulte a seção sobre como abrir arquivos de mídia usando caminhos diretos para os arquivos.
Em execução no Android 10
Se o app for destinado ao Android 10 (nível 29 da API), desative o armazenamento com escopo e continue usando a abordagem do Android 9 e versões anteriores para realizar essa operação.
Em execução no Android 9 ou versões anteriores
Use esta abordagem:
- Seguindo as práticas recomendadas descritas em Solicitar permissões do app,
solicite a permissão
WRITE_EXTERNAL_STORAGE
. - Acesse os arquivos usando caminhos de arquivo diretos.
Gerenciar arquivos que não são de mídia
Esta seção descreve alguns dos casos de uso comuns para gerenciar arquivos que não são de mídia e explica a abordagem de alto nível que seu app pode usar. A tabela a seguir resume cada um desses casos de uso e links para cada uma das seções que contêm mais detalhes.
Caso de uso | Resumo |
---|---|
Abrir um arquivo de documento | Use a mesma abordagem para todas as versões do Android. |
Fazer modificações em arquivos em volumes de armazenamentos secundários | Use uma abordagem para o Android 11. Use uma abordagem diferente para versões anteriores do Android. |
Migrar arquivos existentes de um local de armazenamento legado | Migre seus arquivos para o armazenamento com escopo quando possível. Desative o armazenamento com escopo para o Android 10 quando necessário. |
Compartilhar conteúdo com outros apps | Use a mesma abordagem para todas as versões do Android. |
Armazenar em cache arquivos que não sejam de mídia | Use a mesma abordagem para todas as versões do Android. |
Exportar arquivos que não são de mídia para um dispositivo | Use uma abordagem se o app usar armazenamento com escopo. Use uma abordagem diferente se o app desativar o armazenamento com escopo. |
Abrir um arquivo de documento
Use a intent ACTION_OPEN_DOCUMENT
a fim de solicitar que o usuário escolha um arquivo para abrir usando o seletor do sistema. Se você quiser filtrar os tipos de arquivos que o seletor de sistema apresentará ao usuário, use setType()
ou EXTRA_MIME_TYPES
.
Por exemplo, você pode encontrar todos os arquivos PDF, ODT e TXT usando o seguinte código:
Kotlin
startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" putExtra(Intent.EXTRA_MIME_TYPES, arrayOf( "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt )) }, REQUEST_CODE )
Java
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt }); startActivityForResult(intent, REQUEST_CODE);
Fazer modificações em arquivos em volumes de armazenamento secundários
Os volumes de armazenamento secundário incluem cartões SD. É possível acessar informações sobre um
determinado volume de armazenamento usando a classe
StorageVolume
.
Incorpore a lógica de acordo com as versões do Android em que o app é executado.
No Android 11
Use esta abordagem:
- Use o modelo de armazenamento com escopo.
- Destine o app ao Android 10 (nível 29 da API) ou versões anteriores.
- Declare a
permissão
WRITE_EXTERNAL_STORAGE
. - Execute um destes tipos de acesso:
- Acesso aos arquivos usando a API
MediaStore
. - Acesso aos arquivos usando o caminho direito com APIs como
File
oufopen()
.
- Acesso aos arquivos usando a API
Em versões anteriores
Use o framework de acesso ao armazenamento, que permite que os usuários selecionem o local em um volume de armazenamento secundário em que o app pode modificar o arquivo.
Migrar arquivos existentes de um local de armazenamento legado
Um diretório é considerado um local de armazenamento legado se não for um diretório específico do app ou um diretório compartilhado público. Se o app criar ou consumir arquivos em um local de armazenamento legado, recomendamos que você migre os arquivos do app para locais acessíveis com armazenamento com escopo e faça as mudanças necessárias no app para trabalhar com arquivos no escopo.
Manter o acesso ao local de armazenamento legado para a migração de dados
Seu app precisa manter o acesso ao local de armazenamento legado para migrar os arquivos do app para locais acessíveis com armazenamento com escopo. A abordagem a ser usada depende do nível de API de destino do seu app.
Se o app for destinado ao Android 11
Use a sinalização
preserveLegacyExternalStorage
emtrue
para preservar o modelo de armazenamento legado a fim de permitir que o app possa migrar os dados de um usuário quando ele fizer upgrade para a nova versão do app destinada ao Android 11.Continue a desativar o armazenamento com escopo para que o app possa continuar acessando os arquivos no local de armazenamento legado em dispositivos com o Android 10.
Se o app for direcionado ao Android 10
Desative o armazenamento com escopo para facilitar a manutenção do comportamento do app nas versões do Android.
Migrar dados do app
Quando o app estiver pronto para migração, use esta abordagem:
- Destine o app ao Android 10 ou versões anteriores
- Desative o armazenamento com escopo para que o app tenha acesso aos arquivos que você precisa migrar.
-
Implante código que usa a API
File
para mover arquivos do local atual, em/sdcard/
, para um local acessível pelo armazenamento com escopo:- Mova todos os arquivos particulares do app para o diretório retornado pelo
método
getExternalFilesDir()
. - Mova todos os arquivos compartilhados que não sejam de mídia para um subdiretório dedicado ao app
do diretório
Downloads/
.
- Mova todos os arquivos particulares do app para o diretório retornado pelo
método
- Remova os diretórios de armazenamento legados do app do diretório
/sdcard/
.
Após instalar a nova versão do app, o usuário finaliza o processo de migração de dados no dispositivo. É possível monitorar o processo de migração de toda a base de usuários criando um evento de análise.
Depois que os usuários migrarem os dados, publique outra atualização no app, destinando-o ao Android 11.
Compartilhar conteúdo com outros apps
Para compartilhar os arquivos do seu app com outro, use um
FileProvider
. Para apps que precisam compartilhar arquivos entre si, recomendamos usar um provedor de conteúdo para cada app e sincronizar os dados à medida que eles forem adicionados à coleção.
Armazenar em cache arquivos que não sejam de mídia
A abordagem a ser usada depende do tipo de arquivo que você precisa armazenar em cache.
- Arquivos pequenos ou que contêm informações confidenciais: use
Context#getCacheDir()
. - Arquivos grandes ou que não contêm informações confidenciais: use
Context#getExternalCacheDir()
.
Exportar arquivos que não são de mídia para um dispositivo
Defina um local padrão adequado para armazenar arquivos que não sejam de mídia. Permita que os usuários exportem arquivos de diretórios específicos do app para um local mais acessível. Use as coleções de downloads ou de documentos da MediaStore a fim de exportar os arquivos que não são de mídia para o dispositivo.
Desativar temporariamente o armazenamento com escopo
Antes que o app seja totalmente compatível com o armazenamento com escopo, é possível desativar esse recurso temporariamente, tanto nos testes quanto no app de produção.
Desativar em testes
No Android 10 (nível 29 da API) e versões mais recentes, por padrão, os testes do app são executados em um sandbox de armazenamento. Esse sandbox impede que o app acesse arquivos fora do diretório específico do app e de diretórios compartilhados publicamente.
Se um teste gerar arquivos para o host, como capturas de tela, dados de depuração,
dados de cobertura ou métricas de desempenho, é possível gravar esses arquivos em diretórios
globais. Para fazer isso, adicione a sinalização abaixo ao arcabouço correspondente que
invoca am instrument
:
-e no-isolated-storage 1
Essa sinalização afeta todo o comportamento do caso de teste instrumentado e todo o
código de teste invocado. Portanto, ao usar essa sinalização, não é possível validar a
compatibilidade do app com o armazenamento com escopo. Para a saída de teste, é melhor
gravar no armazenamento com escopo do app que pode ser lido pelo shell. Em seguida, é possível retirar
esse diretório com escopo do app. Para determinar qual diretório vai ser retirado, chame
getExternalMediaDirs()
.
Desativar no app de produção
Se o app for direcionado ao Android 10 (nível 29 da API) ou versões anteriores, você pode desativar temporariamente
o armazenamento com escopo no app de produção. No entanto, se ele for direcionado ao
Android 10, é necessário definir o valor de
requestLegacyExternalStorage
como true
no arquivo de manifesto do app:
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
Para testar como um app direcionado ao Android 10 ou versões anteriores se comporta ao
usar o armazenamento com escopo, ative esse comportamento definindo o valor de
requestLegacyExternalStorage
como false
. Se você estiver testando em um dispositivo com
o Android 11, também é possível usar sinalizações de compatibilidade
de apps para testar o
comportamento do app com ou sem o armazenamento com escopo.
Outros recursos
Para ver mais informações sobre o armazenamento do Android, consulte os materiais abaixo: