Atualizações de armazenamento no Android 11

O Android 11 melhorou ainda mais a plataforma, oferecendo melhor proteção a dados de apps e de usuários no armazenamento externo. A versão de pré-lançamento apresenta várias melhorias que foram anunciadas na Conferência de Desenvolvedores Android (vídeo legendado), como ativação do acesso ao caminho de arquivo bruto para mídia, operações de edição em lote para mídia e uma IU atualizada para o framework de acesso ao armazenamento.

Para facilitar a transição para o uso do armazenamento com escopo, a plataforma apresenta outras melhorias para os desenvolvedores. Para saber mais sobre como migrar seu app para o armazenamento com escopo com base nos casos de uso dele, consulte a seção armazenamento com escopo nesta página, o guia de casos de uso e práticas recomendadas de armazenamento do Android e o artigo Perguntas frequentes sobre armazenamento no Android 11 no Medium (link em inglês).

Como sempre, encorajamos você a enviar feedback para ajudar a moldar a próxima versão do Android. Use o Issue Tracker para enviar seus comentários.

Aplicação de armazenamento com escopo

Para oferecer aos desenvolvedores mais tempo para testes, os apps direcionados ao Android 10 (API de nível 29) ainda podem solicitar o atributo requestLegacyExternalStorage. Essa sinalização permite que os apps desativem temporariamente as mudanças associadas ao armazenamento com escopo, por exemplo, conceder acesso a diretórios e tipos diferentes de arquivos de mídia. Depois que você atualizar seu app para direcioná-lo ao Android 11, o sistema ignorará a sinalização requestLegacyExternalStorage.

Manter a compatibilidade com o Android 10

Se o app desativa o armazenamento com escopo quando for executado em dispositivos com o Android 10, recomendamos que você continue definindo requestLegacyExternalStorage para true no arquivo de manifesto do app. Dessa forma, o app pode continuar a se comportar como esperado em dispositivos com o Android 10.

Migrar dados para diretórios que são visíveis ao usar armazenamento com escopo

Se o app usa o modelo de armazenamento legado e era direcionado anteriormente ao Android 10 ou versões anteriores, ele pode estar armazenando dados em um diretório que não será acessível quando o modelo de armazenamento com escopo for ativado. Antes de direcioná-lo ao Android 11, migre os dados para um diretório compatível com o armazenamento com escopo. Na maioria dos casos, é possível migrar os dados para o diretório específico do app.

Caso tenha dados para migrar, é possível preservar o modelo de armazenamento legado quando um usuário faz upgrade para a nova versão do app direcionada ao Android 11. Dessa forma, o usuário mantém o acesso aos dados do app armazenados nos diretórios onde o app salvou os dados anteriormente. Para ativar o modelo de armazenamento legado para um upgrade, defina o atributo preserveLegacyExternalStorage como true no manifesto do app.

Observação: a maioria dos apps não precisa usar preserveLegacyExternalStorage. Essa sinalização é projetada apenas para a situação em que você migrou os dados do app para um local compatível com o armazenamento com escopo e quando você quer que os usuários mantenham o acesso aos dados ao atualizar o app. Usar essa sinalização dificulta o teste de como o armazenamento com escopo afeta os usuários porque, quando eles atualizam o app, ele continua a usar o modelo de armazenamento legado.

Se você usar preserveLegacyExternalStorage, o modelo de armazenamento legado permanecerá em vigor até que o usuário desinstale o app. Se o usuário instalar ou reinstalar o app em um dispositivo com o Android 11, o app não poderá não utilizar o modelo de armazenamento com escopo, independentemente do valor de preserveLegacyExternalStorage.

Testar armazenamento com escopo

Para ativar o armazenamento com escopo no app, independentemente da versão do SDK de destino do app e dos valores da sinalização do manifesto, ative as seguintes sinalizações de compatibilidade de apps:

Para desativar o armazenamento com escopo e usar o modelo de armazenamento legado, desmarque as duas sinalizações.

Gerenciar armazenamento do dispositivo

No Android 11, os apps que usam o modelo de armazenamento com escopo podem acessar apenas os próprios arquivos de cache específicos do app. Se o app precisar gerenciar o armazenamento do dispositivo, faça o seguinte:

  1. Verifique o espaço livre invocando a ação da intent ACTION_MANAGE_STORAGE.
  2. Se não houver espaço livre suficiente no dispositivo, solicite ao usuário que autorize a limpeza de todos os caches. Para fazer isso, invoque a ação da intent ACTION_CLEAR_APP_CACHE.

Diretório específico do app no armazenamento externo

No Android 11, os apps não podem criar o próprio diretório específico do app no armazenamento externo. Para acessar o diretório que o sistema fornece para seu app, chame getExternalFilesDirs().

Acesso a arquivos de mídia

Para facilitar o acesso a mídia e manter a privacidade do usuário, o Android 11 introduz os recursos a seguir.

Realizar operações em lote

Para consistência entre os dispositivos e maior conveniência do usuário, o Android 11 adiciona vários métodos à API MediaStore. Esses métodos são particularmente úteis para apps que querem um fluxo otimizado para modificar arquivos de mídia específicos, como, por exemplo, editar uma foto local.

Os métodos adicionados são os seguintes:

createWriteRequest()
Solicita que o usuário conceda acesso de gravação ao seu app para o grupo especificado de arquivos de mídia.
createFavoriteRequest()
Solicita que o usuário marque os arquivos de mídia especificados como "favoritos" no dispositivo. Todo app com acesso de leitura verá que o usuário marcou o arquivo como "favorito".
createTrashRequest()

Solicita que o usuário coloque os arquivos de mídia especificados na lixeira do dispositivo. Os itens na lixeira são excluídos permanentemente após um período definido pelo sistema.

createDeleteRequest()

Solicita que o usuário exclua permanentemente os arquivos de mídia especificados imediatamente sem colocá-los na lixeira antes.

Depois de chamar um desses métodos, o sistema cria um objeto PendingIntent. Depois que o app invoca essa intent, os usuários veem uma caixa de diálogo que solicita o consentimento deles para que o app atualize ou exclua os arquivos de mídia especificados.

Por exemplo, veja como estruturar uma chamada para createWriteRequest():

Kotlin

val urisToModify = /* A collection of content URIs to modify. */
val editPendingIntent = MediaStore.createWriteRequest(contentResolver,
        urisToModify)

// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
    null, 0, 0, 0)

Java

List<Uri> urisToModify = /* A collection of content URIs to modify. */
PendingIntent editPendingIntent = MediaStore.createWriteRequest(contentResolver,
                  urisToModify);

// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.getIntentSender(),
    EDIT_REQUEST_CODE, null, 0, 0, 0);

Avalie a resposta do usuário e continue ou, se ele não consentir, explique por que seu app precisa da permissão:

Kotlin

override fun onActivityResult(requestCode: Int, resultCode: Int,
                 data: Intent?) {
    ...
    when (requestCode) {
        EDIT_REQUEST_CODE ->
            if (resultCode == Activity.RESULT_OK) {
                /* Edit request granted; proceed. */
            } else {
                /* Edit request not granted; explain to the user. */
            }
    }
}

Java

@Override
protected void onActivityResult(int requestCode, int resultCode,
                   @Nullable Intent data) {
    ...
    if (requestCode == EDIT_REQUEST_CODE) {
        if (resultCode == Activity.RESULT_OK) {
            /* Edit request granted; proceed. */
        } else {
            /* Edit request not granted; explain to the user. */
        }
    }
}

Você pode usar esse mesmo padrão geral com createFavoriteRequest(), createTrashRequest() e createDeleteRequest().

Acessar arquivos usando caminhos de arquivos diretos e bibliotecas nativas

Para ajudar seu app a funcionar melhor com bibliotecas de mídia de terceiros, o Android 11 permite que você use APIs diferentes da API MediaStore para acessar arquivos de mídia do armazenamento compartilhado. Em vez disso, você pode optar por acessar arquivos de mídia diretamente usando uma das seguintes APIs:

  • A API File
  • Bibliotecas nativas, como fopen()

Se o app não tiver permissões de armazenamento, você poderá acessar os arquivos de mídia atribuídos a ele usando caminhos de arquivo diretos. Se o app tiver a permissão READ_EXTERNAL_STORAGE, ele poderá acessar todos os arquivos de mídia usando caminhos de arquivo diretos, independentemente de estarem atribuídos a ele.

Se você acessar arquivos de mídia diretamente, recomendamos desativar o armazenamento com escopo definindo requestLegacyExternalStorage como true no arquivo de manifesto do app. Dessa forma, o app se comportará como o esperado em dispositivos com o Android 10.

Desempenho

Quando você executa leituras sequenciais de arquivos de mídia usando caminhos de arquivo diretos, o desempenho é comparável ao da API MediaStore.

No entanto, quando você executa leituras e gravações aleatórias de arquivos de mídia usando caminhos de arquivo diretos, o processo pode ser até duas vezes mais lento. Nessas situações, recomendamos o uso da API MediaStore.

Valores disponíveis do armazenamento de mídia

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 esteja sempre disponível. Esteja preparado para lidar com qualquer erro de E/S baseado em arquivo que possa ocorrer.

Para criar ou atualizar um arquivo de mídia, por outro lado, não use o valor da coluna DATA. Em vez disso, use os valores das colunas DISPLAY_NAME e RELATIVE_PATH.

Acesso a dados de outros apps

Para proteger a privacidade do usuário, o Android 11 aumenta as restrições de acesso do seu app a diretórios privados de outros apps.

Acesso a diretórios de dados no armazenamento interno

Detalhes da mudança

Nome da mudança: APP_DATA_DIRECTORY_ISOLATION

ID da mudança: 143937733

Como ativar

Ao testar a compatibilidade do app com o Android 11, é possível ativar ou desativar essa mudança usando os seguintes comandos ADB:

adb shell am compat enable (143937733|APP_DATA_DIRECTORY_ISOLATION) PACKAGE_NAME
adb shell am compat disable (143937733|APP_DATA_DIRECTORY_ISOLATION) PACKAGE_NAME

Para ver mais informações sobre o framework de compatibilidade e a ativação ou desativação de mudanças, consulte Testar a compatibilidade do app com o Android 11.

O Android 9 (nível da API 28) começou a restringir quais apps podiam tornar os arquivos nos diretórios de dados no armazenamento interno deles amplamente acessíveis para outros apps. Os apps direcionados ao Android 9 ou versões mais recentes não podem tornar os arquivos dos diretórios de dados amplamente acessíveis.

O Android 11 amplia essa restrição. Caso seu app seja direcionado ao Android 11, ele não poderá acessar arquivos em diretórios de dados de outros apps, mesmo que o outro app seja direcionado ao Android 8.1 (nível da API 27) ou anterior e tenha tornado os arquivos no diretório de dados amplamente acessíveis.

Acesso a diretórios específicos do app no armazenamento externo

No Android 11, os apps não podem mais acessar arquivos em qualquer diretório dedicado e específico do app de outros aplicativos no armazenamento externo.

Restrições de acesso a documentos

Para dar aos desenvolvedores tempo para testes, as seguintes mudanças relacionadas ao Framework de acesso ao armazenamento (SAF, na sigla em inglês) a seguir entram em vigor somente se o app for direcionado ao Android 11.

Acesso a diretórios

Não é mais possível usar a ação da intent ACTION_OPEN_DOCUMENT_TREE para solicitar acesso aos seguintes diretórios:

  • O diretório raiz do volume de armazenamento interno.
  • O diretório raiz de cada volume do cartão SD que o fabricante do dispositivo considera confiável, independentemente do cartão ser emulado ou removível. Um volume confiável é aquele que um app pode acessar na maioria das vezes.
  • O diretório Download.

Acesso a arquivos

Não é mais possível usar a ACTION_OPEN_DOCUMENT_TREE ou a ação da intent ACTION_OPEN_DOCUMENT para solicitar que o usuário selecione arquivos individuais dos seguintes diretórios:

  • O diretório Android/data/ e todos os subdiretórios
  • O diretório Android/obb/ e todos os subdiretórios.

Testar a mudança

Para testar essa mudança de comportamento, faça o seguinte:

  1. Invoque uma intent com a ação ACTION_OPEN_DOCUMENT. Verifique se os diretórios Android/data/ e Android/obb/ não aparecem.
  2. Realize uma das seguintes ações:
  3. Invoque uma intent com a ação ACTION_OPEN_DOCUMENT_TREE. Verifique se o diretório Download aparece e se o botão de ação associado com o diretório está esmaecido.

Permissões

O Android 11 introduz as seguintes mudanças relacionadas às permissões de armazenamento:

Criar para qualquer versão

A primeira caixa de diálogo apresenta um link chamado Permitir nas configurações.
Figura 1. Caixa de diálogo exibida quando um app usa o armazenamento com escopo e solicita a permissão READ_EXTERNAL_STORAGE.

As seguintes mudanças entrarão em vigor no Android 11, independentemente da versão do SDK de destino do seu app:

  • A permissão de ambiente de execução Armazenamento foi renomeada para Arquivos e mídia.
  • Se o app não tiver desativado o armazenamento com escopo e solicitar a permissão READ_EXTERNAL_STORAGE, os usuários verão uma caixa de diálogo diferente em comparação ao Android 10. A caixa de diálogo indica que o app está solicitando acesso a fotos e mídia, como mostrado na Figura 1.

    Os usuários podem ver quais apps têm a permissão READ_EXTERNAL_STORAGE nas configurações do sistema. Na página Configurações > Privacidade > Gerenciador de permissões > Arquivos e mídia cada app com a permissão estará listado em Permitido para todos os arquivos.

    Observação: se o app for direcionado ao Android 11, lembre-se que esse acesso a "todos os arquivos" é somente para leitura. Para ler e gravar em todos os arquivos no armazenamento compartilhado usando esse app, a permissão Acesso a todos os arquivos é necessária.

Criar para o Android 11

Se o app for direcionado ao Android 11, tanto a permissão WRITE_EXTERNAL_STORAGE quanto a permissão privilegiada WRITE_MEDIA_STORAGE não fornecerão mais acesso adicional.

Lembre-se de que, em dispositivos que executam o Android 10 (API de nível 29) ou mais recente, seu app pode contribuir para coleções de mídia bem definidas, como MediaStore.Downloads, sem solicitar permissões relacionadas ao armazenamento. Saiba mais sobre como solicitar apenas as permissões necessárias ao trabalhar com arquivos de mídia no seu app.

Acesso a todos os arquivos

A maioria dos apps que exigem acesso ao armazenamento compartilhado pode seguir as práticas recomendadas de armazenamento com escopo, como o framework de acesso ao armazenamento ou a API MediaStore. No entanto, alguns apps têm um caso de uso principal que requer amplo acesso a arquivos em um dispositivo, mas não podem fazer isso de forma eficiente usando as práticas recomendadas de armazenamento adequado para privacidade.

Por exemplo, o caso de uso principal de um app antivírus pode exigir a verificação regular de muitos arquivos em diretórios diferentes. Se essa verificação exigir interações repetidas do usuário para selecionar diretórios usando o seletor de arquivos do sistema, ela poderá proporcionar uma experiência ruim ao usuário. Outros casos de uso, como apps de gerenciamento de arquivos, apps de backup e restauração e apps de gerenciamento de documentos, podem exigir considerações semelhantes.

Para solicitar um acesso especial de app chamado Acesso a todos os arquivos do usuário, um app pode:

  1. declarar a permissão MANAGE_EXTERNAL_STORAGE no manifesto;
  2. usar a ação da intent ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION para direcionar os usuários a uma página de configurações do sistema em que é possível ativar a seguinte opção: Permitir acesso para gerenciar todos os arquivos para o app.

Para determinar se o app recebeu a permissão MANAGE_EXTERNAL_STORAGE, chame Environment.isExternalStorageManager().

A permissão MANAGE_EXTERNAL_STORAGE concede o seguinte:

  • Acesso de leitura e gravação a todos os arquivos no armazenamento compartilhado.

  • Acesso ao conteúdo da tabela MediaStore.Files.

  • Acesso ao diretório raiz da unidade USB em qualquer lugar (OTG) e do cartão SD.

  • Acesso de gravação a todos os diretórios de armazenamento interno⁠, exceto /Android/data/, /sdcard/Android e a maioria dos subdiretórios de /sdcard/Android. Esse acesso de gravação inclui acesso ao caminho de arquivo.

    Os apps que recebem essa permissão ainda não podem acessar os diretórios específicos do app que pertencem a outros apps porque eles aparecem como subdiretórios de Android/data/ em um volume de armazenamento.

Quando um app tem a permissão MANAGE_EXTERNAL_STORAGE, ele pode acessar esses arquivos e diretórios adicionais usando a API MediaStore ou os caminhos de arquivo. No entanto, ao usar o framework de acesso ao armazenamento, você só poderá acessar um arquivo ou diretório se puder fazer isso sem a permissão MANAGE_EXTERNAL_STORAGE.

Ativar para testes

Para explorar como a permissão de acesso a todos os arquivos afeta seu app, ative-a para testes. Para fazer isso, execute o seguinte comando na máquina conectada ao dispositivo de teste:

adb shell appops set --uid PACKAGE_NAME MANAGE_EXTERNAL_STORAGE allow

Aviso do Google Play

Esta seção fornece um aviso aos desenvolvedores que publicam apps no Google Play.

Para limitar o acesso amplo ao armazenamento compartilhado, a Google Play Store atualizou a política para avaliar apps destinados ao Android 11 e solicitar acesso a todos os arquivos por meio da permissão MANAGE_EXTERNAL_STORAGE.

Solicite o MANAGE_EXTERNAL_STORAGE somente quando seu app não puder usar efetivamente as APIs que proporcionam mais privacidade, como Storage Access Framework ou Media Store. Além disso, a aplicação da permissão precisa estar dentro dos usos permitidos e ser diretamente vinculada à função principal do app. Se o app incluir um caso de uso semelhante aos exemplos a seguir, é provável que você possa solicitar a permissão MANAGE_EXTERNAL_STORAGE:

  • Gerenciadores de arquivos
  • Backup e restauração
  • Apps de antivírus
  • Apps de gerenciamento de documentos

Devido a considerações relacionadas ao COVID-19, os apps destinados ao Android 11 e que precisam da permissão MANAGE_EXTERNAL_STORAGE não podem ser enviados ao Google Play até o início de 2021. Isso inclui apps novos e atualizações. Para saber mais, leia a política atualizada na Central de Ajuda de Políticas.

Por enquanto, se você achar que a permissão de gerenciamento de armazenamento externo é necessária para o app, não atualize o SDK de destino para o Android 11. Caso o app seja direcionado ao Android 10, use a sinalização requestLegacyExternalStorage.