[Android Framework Series] Capítulo 17 Modo Sandbox do Android Q (armazenamento com escopo)

1. Fundo

O capítulo anterior [Android Framework Series] Capítulo 16 Storage Access Framework (SAF) analisou principalmente a estrutura de acesso ao armazenamento (SAF) introduzida no Android 4.4 存储访问框架(SAF). Neste capítulo analisamos Android10(Q)o armazenamento relacionado e entendemos seus métodos de armazenamento restritos.

GooglePara dar aos usuários mais controle sobre seus arquivos e limitar a confusão de arquivos, a forma como você acessa o armazenamento do seu dispositivo Android Q mudou .App

Antes de 1.1 Android Q

Contanto que o programa obtenha READ_EXTERNAL_STORAGEpermissão, ele poderá ler livremente o diretório público de armazenamento externo;
desde que o programa obtenha WRITE_EXTERNAL_STORAGEpermissão, ele poderá criar livremente novos arquivos ou pastas no diretório público gravados no armazenamento externo.
Insira a descrição da imagem aqui

1.2 Android Q e posterior

Então o Google propôs isso no Android Q 分区存储, pretendendo limitar o uso de diretórios públicos em armazenamento externo por programas .
O armazenamento particionado não tem impacto nos diretórios privados de armazenamento interno e nos diretórios privados de armazenamento externo.
Insira a descrição da imagem aqui

2 Modo sandbox

2.1 O Android Q estipula que o aplicativo tenha duas visualizações de modo de espaço de armazenamento: Visualização herdada e Visualização filtrada.

2.1.1 Visualização herdada (modo de compatibilidade)

Quando o projeto targetSdkVersion <= 28, o modo de compatibilidade é usado por padrão no dispositivo AndroidQ, o método de armazenamento é o mesmo de Android Qantes Appe o acesso Sdcardé o mesmo, com direitos de acesso completos.

2.1.2 Visualização Filtrada (modo sandbox)

Quando o projeto targetSdkVersion > 28, o dispositivo AndroidQ Appsó pode acessar diretamente App-specificarquivos de diretório e não tem permissão para acessar App-specificarquivos externos. O acesso a outros diretórios só pode ser fornecido por meio de MediaStore, SAFou outros aplicativos ContentProvider.

2.2 O armazenamento com escopo divide o espaço de armazenamento em duas partes

2.2.1 Diretório público do cartão SD: Downloads, Documentos, Imagens, DCIM, Filmes, Música, Toques

  1. Os arquivos no diretório público Appnão serão excluídos após a desinstalação
  2. Pode ser acessado através SAFda MediaStoreinterface

2.2…2 diretório privado de dados/dados (diretório específico do aplicativo)

  1. Para Filtered View App, App-specifico diretório só pode ser acessado diretamente por você
  2. AppDesinstale e os dados serão apagados.

2.3 Impacto de compatibilidade

Scoped StorageTem um grande impacto sobre App访问存储方式, App数据存放e App间数据共享.

2.4 Adaptação

Para adaptação específica, consulte a documentação oficial.

2.4.1 Visualização em execução do aplicativo

O sistema determina o modo de execução do aplicativo através do seguinte:

  1. App TargetSDK > 28,padrãoFiltered View(沙箱模式)
  1. App TargetSDK <= 28, declara a permissão READ_EXTERNAL_STORAGE ou WRITE_EXTERNAL_STORAGE, padrãoLegacy View(兼容模式)
  1. O aplicativo pode definir requestLegacyExternalStorage por meio de AndroidManifest.xml e selecionar o método correspondente:
    declarado READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGEpermissão (ignorado se não declarado):
    requestLegacyExternalStorage=truesignificaLegacy View(兼容模式)
    requestLegacyExternalStorage=falseFiltered View(沙箱模式)
    (注意:该方式Android11后失效了)

    Insira a descrição da imagem aqui
  1. Os aplicativos do sistema podem solicitar android.permission.WRITE_MEDIA_STORAGEpermissões do sistema e também ter permissões de espaço de armazenamento total e acessar todos os arquivos.No entanto, no teste CTS, apenas aplicativos que não têm interação do usuário e são visíveis podem se inscrever. Referência específica 《Android Bootcamp 2019 - Privacy Overview.pdf》.
  1. O aplicativo é propriedade quando as seguintes condições são atendidas
    : ① Declaração INSTALL_PACKAGESou 动态申请INSTALL_PACKAGESpermissão
    ② Propriedade WRITE_EXTERNAL_STORAGE权限
    ③ Propriedade do aplicativo 外置存储空间Read、Write权限.
    Porém, Environment.isExternalStorageLegacya julgar pela interface, o retorno não é necessariamente uma Visualização Legada.

2.4.2 Determine o modo de execução atual do aplicativo

Para determinar em qual modo o aplicativo atual está sendo executado, você pode usar esta API para determinar:

Environment.isExternalStorageLegacy();

2.5 Lendo e escrevendo diretórios públicos

Depois que o aplicativo é iniciado Filtered View, ele só pode acessar a si mesmo diretamente App-specific目录, portanto, Android Qsão fornecidos dois métodos de acesso ao diretório público:

2.5.1 Uri definido pelo MediaStore

MediaStoreOs seguintes tipos de acesso são fornecidos Uri, e o objetivo do acesso é alcançado através da pesquisa dos dados Uri correspondentes.
Cada um dos seguintes tipos é dividido em três tipos Uri, Internal, External, 可移动存储:

Áudio

  1. Interno: MediaStore.Audio.Media.INTERNAL_CONTENT_URI
    content://media/internal/audio/media。
  2. Externo: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    content://media/external/audio/media。
  3. Armazenamento removível: MediaStore.Audio.Media.getContentUri
    content://media//audio/media.

Vídeo

  1. Interno: MediaStore.Video.Media.INTERNAL_CONTENT_URI
    content://media/internal/video/media。
  2. Externo: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    content://media/external/video/media。
  3. Armazenamento removível: MediaStore.Video.Media.getContentUri
    content://media//video/media.

Imagem

  1. Interno: MediaStore.Images.Media.INTERNAL_CONTENT_URI
    content://media/internal/images/media。
  2. Externo: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    content://media/external/images/media。
  3. Armazenamento removível: MediaStore.Images.Media.getContentUri
    content://media//images/media.

Arquivo

  1. MediaStore. Files.Media.getContentUri
    content://media//file。

Transferências

  1. Interno: MediaStore.Downloads.INTERNAL_CONTENT_URI
    content://media/internal/downloads。
  2. Externo: MediaStore.Downloads.EXTERNAL_CONTENT_URI
    content://media/external/downloads。
  3. Armazenamento removível: MediaStore.Downloads.getContentUri
    content://media//downloads.
2.5.1.1 Obtenha todos os volumes

Para o Uri descrito anteriormente, getContentUricomo obter todos eles pode ser feito da seguinte maneira:

for(String volume:MediaStore.getExternalVolumeNames(this)){
    
    
	MediaStore.Audio.Media.getContentUri(volume);
}
2.5.1.2 Relacionamento entre Uri e diretório público

MediaProviderPara que o App seja armazenado em um arquivo de diretório público, ele é determinado pelo Uri no método. O caminho relativo é ContentResolver insertmostrado na tabela a seguir , e o arquivo completo é: content://media//<Uri path>.<Uri路径>

Insira a descrição da imagem aqui

2.5.1.3 Permissões

MediaStoreAtravés de diferentes métodos Uri, os usuários podem adicionar, excluir (se os arquivos não puderem ser excluídos por meio do File Uri, será necessário usar a interface SAF) e modificar.
As permissões correspondentes do aplicativo são as seguintes:
Insira a descrição da imagem aqui

2.5.1.4 Consultar arquivos

Consultando ContentResolverconteúdos diferentes com base em Uri diferentes:

  try (Cursor c = getContentResolver()
                .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, null, null, null)) {
    
    
            while (c.moveToNext()) {
    
    
                Uri contentUri =
                        ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, c.getLong(0));
            }
        }

PS: Durante MediaStore.Fileso processo Query, apenas fotos, vídeos e arquivos de áudio serão exibidos.

2.5.1.5 Lendo arquivos

Através ContentResolver queryda interface, a leitura do arquivo após localizá-lo pode ser feita da seguinte forma:

  1. Através ContentResolver openFileDescriptorda interface, selecione o método de abertura correspondente,
    por exemplo, "r" significa leitura, "w" significa escrita e o ParcelFileDescriptortipo de retorno FD.
  2. Acessado Thumbnailatravés ContentResolver loadThumbnailda interface.
    Ao passar o tamanho, MediaProvidero tamanho especificado é retornado Thumbnail.
  3. O código nativo acessa arquivos.
    Se o código nativo precisar acessar arquivos, você pode consultar os seguintes métodos:
    openFileDescriptorRetornando ParcelFileDescriptor
    ParcelFileDescriptor.detachFd()Lendo FD
    FDPassando para Nativeo código da camada
    AppPrecisa ser responsável pelo fechamento através closeda interfaceFD
   	ParcelFileDescriptor parcelFd = resolver.openFileDescriptor(uri, file0penMode);
	if (parcelFd != null) {
    
    
	      int fd = parcelFd.detachFd();
	      // Pass the integer value "fd" into your native code. Remember to call
	      // close(2) on the file descriptor when you're done using it.
	}
2.5.1.6 Criar novo arquivo

Se precisar armazenar um novo arquivo em um diretório público, você precisará ContentResolver insertusar uma interface diferente Urie optar por armazená-lo em um diretório diferente.
Insira a descrição da imagem aqui

2.5.1.7 Modificar arquivos

Se precisar modificar um arquivo multimídia, você precisa ContentResolver queryencontrar o Uri do arquivo correspondente através da interface.
Se você não criou um novo arquivo, você precisa prestar atenção à descrição em 2.5.1.3 Permissões. Você precisa aplicar WRITE_EXTERNAL_STORAGE权限ou catch RecoverableSecurityExceptionuma caixa pop-up dará ao usuário uma escolha.
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Através da interface a seguir, obtenha o arquivo que precisa ser modificado FDou OutputStream:

  1. getContentResolver().openOutputStream(contentUri)
    obtém o OutputStream do arquivo correspondente.
  2. getContentResolver().openFile ou getContentResolver().openFileDescriptor
    abre o arquivo através de openFile ou openFileDescriptor. Você precisa selecionar Mode como "w", que indica permissão de gravação. Essas interfaces retornam um ParcelFileDescriptor.
    getContentResolver().openFileDescriptor(contentUri,“w”);
    getContentResolver().openFile(contentUri,“w”,null);
2.5.1.8 Excluir arquivos

Exclua arquivos por meio da interface ContentResolver e o Uri é o Uri da consulta:

getContentResolver().delete(contentUri,null,null);

2.5.2 Através da interface SAF

2.5.2.1 Introdução ao SAF

SAF, isto é , fornecendo aos usuários a capacidade de abrir e navegar por arquivos Storage Access Frameworkselecionando diferentes arquivos . DocumentsProviderPodemos olhar para o capítulo anterior

O Android fornece o seguinte por padrão DocumentsProvider:
MediaDocumentsProvider, ExternalStorageProvider, DownloadStorageProvider.
A diferença entre eles é:
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

Nesta imagem, existem três áreas, a saber:

  1. MediaDocumentsProvide
  2. DownloadStorageProvider
  3. Provedor de armazenamento externo
  4. Fornecedor de documentos de terceiros
2.5.2.2 Como usar

Consulte a documentação oficial para obter detalhes

O método geral é o seguinte:

  1. Selecione um único arquivoInsira a descrição da imagem aqui
  2. Selecione o diretório,
    Insira a descrição da imagem aqui
    o programa de gerenciamento de arquivos e o programa de limpeza. Você pode usar este método para obter todas as permissões de gerenciamento para o diretório e subdiretórios correspondentes.
  3. crie um novo arquivo
    Insira a descrição da imagem aqui
  4. excluir
DocumentsContract.deleteDocument(getContentResolver(),uri);
  1. Rever

①Obter OutputStream

getContentResolver().openOutputStream(uri);

② Obtenha o ParcelFileDescriptor gravável

getContentResolver().openFileDescriptor(contentUri,"w");
getContentResolver().openFile (contentUri,"w",null);

Referência específica de demonstração

2.6 Acesse diretórios específicos do aplicativo

Existem duas situações de acesso App-specific, a primeira é o acesso App自身App-specific目录e a segunda é o acesso 其他App目录文件.

2.6.1 Diretório específico do próprio aplicativo

Android Q, se o aplicativo for iniciado Filtered View, ele só poderá acessar diretamente os arquivos em seu próprio diretório:

  1. As interfaces Environment.getExternalStorageDirectory e getExternalStoragePublicDirectory
    estão obsoletas no Android Q. O aplicativo é uma visualização filtrada e não pode acessar diretamente este diretório.
  2. Acessar
    o App através de Arquivo ("/sdcard/") é uma Visualização Filtrada e não pode acessar diretamente este diretório.
  3. Obtenha o diretório específico do aplicativo
    Obtenha a interface de mídia: getExternalMediaDirs
    Obtenha a interface de cache: getExternalCacheDirs
    Obtenha a interface Obb: getObbDirs
    Obtenha a interface de dados: getExternalFilesDirs

2.6.2 Arquivos multimídia no diretório específico do aplicativo

Arquivos multimídia dentro do diretório específico do aplicativo:

  1. O acesso próprio do aplicativo App-specificé igual ao diretório próprio do aplicativo 2.6.1
  2. Acesso de outros aplicativos
    ① Por padrão , os arquivos multimídia contidos Media Scannernão serão verificados . Se a verificação for necessária, ela precisará ser adicionada ao banco de dados. O método de acesso é o mesmo do 2.5 lendo e gravando diretórios públicos. ②O aplicativo é compartilhado por meio de compartilhamentoApp-specificMediaScannerConnection.scanFileMediaProvider

    ContentProvider

2.6.3 Outros arquivos do diretório de aplicativos

O aplicativo é uma visualização filtrada. Outros aplicativos não podem acessar diretamente o diretório privado do aplicativo atual. Você precisa usar o seguinte método:

2.6.3.1 Através de arquivo SAF
  1. Compartilhe a personalização do aplicativoDocumentsProvider

A personalização do aplicativo DocumentsProviderrequer as seguintes etapas:
a) EspecifiqueDocumentsProvider
Insira a descrição da imagem aqui

b) DocumentsProviderImplemente a interface básica:
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

  1. Acesse o App ACTION_OPEN_DOCUMENTe comece a navegar
    Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

2.6.3.2 Compartilhando aplicativo para implementar FileProvider

Referência de uso específica do FileProvider

Aqui está um resumo das etapas gerais:

  1. FileProvider de aplicativo especificado
    Insira a descrição da imagem aqui

  2. Especifique o caminho do arquivo, o arquivo de configuração deve ser colocado em res/xml
    Insira a descrição da imagem aqui

  3. Obter compartilhamento Uri
    Insira a descrição da imagem aqui

  4. Defina permissões e envie Uri
    Insira a descrição da imagem aqui
    Insira a descrição da imagem aqui

  5. Receba o aplicativo e defina o interfiltro aceito
    Insira a descrição da imagem aqui

  6. Receber e processar Uri
    Insira a descrição da imagem aqui

2.6.3.3 Provedor privado personalizado do aplicativo

Os aplicativos podem ser personalizados ContentProvider, especialmente 内部文件共享, mas a interação da interface do usuário não é esperada.

2.7 MediaStore

2.7.1 Campo MediaStore_data

MediaStoreEm, DATA即(_data)字段, Android Qcomeçou a ser abandonado em. Ler e gravar arquivos requer aprovação openFileDescriptor.

2.7.2 Arquivo MediaStore Status pendente

No Android Q, MediaStorefoi adicionado um IS_PENDING Flagpara marcar Pendingo status do arquivo atual.
Outros aplicativos MediaStoreconsultam arquivos. Se nenhuma setIncludePendinginterface estiver definida, os arquivos definidos com status Pendente não poderão ser consultados. Isso dá ao aplicativo acesso exclusivo a esse arquivo. Usado em algumas situações, como durante o download: Durante o download, o arquivo está no status Pendente e o download é concluído, e o status Pendente do arquivo é definido como 0.
Insira a descrição da imagem aqui

2.7.3 MediaColumns.RELATIVE_PATH define o caminho de armazenamento

No Android Q, ao MediaStorearmazenar arquivos no diretório público, além do diretório de primeiro nível de cada espaço de armazenamento especificado no relacionamento entre Uri e diretório público na Seção 2.5.1.2, o diretório secundário para armazenamento pode ser especificado por meio de MediaColumns. RELATIVE_PATH. Este diretório pode ser criado em vários níveis, o código específico é o seguinte:

  1. O método de inserção ContentResolver
    especifica o diretório de armazenamento por meio de valores.put(Media.RELATIVE_PATH,"Pictures/album/family "). Entre eles, Pictures é um diretório de primeiro nível e album/family é um subdiretório.
  2. O método de atualização ContentResolver
    especifica o diretório de armazenamento por meio de valores.put(Media.RELATIVE_PATH,"Pictures/album/family "). Através do método de atualização, o local de armazenamento pode ser movido.

2.7.4 Acessar metadados Exif da imagem

No Android Q, se o aplicativo precisar acessar os metadados Exif na imagem, ele precisará fazer o seguinte:

  1. AplicarACCESS_MEDIA_LOCATION权限
  2. O código de demonstração é o MediaStore.setRequireOriginal返回新Uri
    seguinte:
    Insira a descrição da imagem aqui

2.7.5 Visualização filtrada do aplicativo, resumo das permissões de acesso

As permissões do aplicativo para acessar diferentes diretórios são resumidas a seguir:
Insira a descrição da imagem aqui

2.7.6 Desinstalação de aplicativos

Se o aplicativo AndroidManifest.xmldeclarar em: android:hasFragileUserData="true"
Ao desinstalar o aplicativo, você será questionado se deseja reter os dados do aplicativo:
Insira a descrição da imagem aqui

2.7.7 Migração de dados de aplicativos

No Android Q, App TargetSDK>=Qo padrão é Filtered View. Se o aplicativo for uma visualização filtrada, isso envolverá migração de dados, caso contrário, os dados antigos ficarão inutilizáveis. Você pode iniciar a migração de dados a partir dos seguintes aspectos:

  1. O aplicativo precisa Legacy Viewser baixado para ter permissão total para operar o armazenamento
  2. Os arquivos de aplicativos armazenados em áreas não públicas podem ser acessados SAF访问​​selecionando arquivos de diretório por meio do SAF, e os usuários podem optar por acessar os arquivos de aplicativos.
    Insira a descrição da imagem aqui
  3. O aplicativo pode colocar os arquivos que precisam ser salvos:
    Images, Video, Audiono diretório público correspondente. Outros arquivos podem ser colocados Downloadsabaixo sem excluir os arquivos após a desinstalação.

2.7.8 Consultas do MediaStore

Ao usar MediaStorepara realizar queryações, Projectionao usar, Column Namedeve MediaStoreser definido em.

2.8 Permissão WRITE_MEDIA_STORAGE

2.8.1 Antecedentes

WRITE_MEDIA_STORAGEÉ uma permissão muito poderosa que permite ao App obter acesso a todos os dispositivos de armazenamento. Permissão para acessar todos os dispositivos de armazenamento, esta deve ser dada apenas ao Media Stack.

2.8.2 Impacto de compatibilidade

No sistema Android, está estipulado que o grupo de usuários WRITE_MEDIA_STORAGEpode ser obtido media_rw:
Insira a descrição da imagem aqui

  1. Para todos os dispositivos de armazenamento removíveis, como cartões T e discos U, quando montados no Android, os aplicativos comuns têm apenas permissões de leitura e nenhuma permissão de gravação. Somente aplicativos do grupo de usuários media_rw podem gravar em dispositivos de armazenamento removíveis.
  2. Para armazenamento com escopo no Android Q, você pode usar essa permissão para configurar o aplicativo para ser executado em modo de compatibilidade.
  3. O Android CTS realizará testes. Aplicativos inicializáveis ​​pelo usuário não podem solicitar essa permissão.
    Para obter detalhes, consulte "Android Bootcamp 2019 - Privacy Overview.pdf".

2.8.3 Adaptação

Se o aplicativo precisar acessar Mediaou 外置存储设备, você poderá usar MediaStoreou Storage Access Framework(SAF)接口.

3 Resumo

Ok, aqui está um resumo:

  1. App TargetSDK > 28 即 Android10(Q)及以上Projeto, o Google restringiu o modo sandbox de armazenamento. No uso recomendado Android10(Q)以上的设备, 私有目录data/dataele não pode mais ser acessado diretamente 外部SD卡存储目录. Se precisar usá-lo , você precisa acessá-lo 外部SD卡存储目录através da interface, e só pode ser acessado , como ,,, , , , , etc Esses diretórios externos de armazenamento de cartão SD (diretórios públicos) podem ser acessados ​​por todos os aplicativos, portanto, não são muito seguros.SAFMediaStore特定的外部SD卡存储目录DownloadsDocumentsPicturesDCIMMoviesMusicRingtones
  2. App TargetSDK <= 28 即 Android10(Q)以下O projeto é irrestrito, desde que tenha WRITE_MEDIA_STORAGEpermissões READ_MEDIA_STORAGE. Portanto, se você realmente não deseja alterar o armazenamento SD externo, altere o targetSdk do projeto para <=28.
  3. Quanto SAFao método MediaStorede acesso à interface 外部SD卡存储特定目录, consulte a descrição acima ou a documentação oficial para obter detalhes. Aqui está uma demonstração de MediaStorecomo usá-lo para sua referência 外部SD卡存储特定目录. Não se esqueça de clicar em Estrela.

Acho que você gosta

Origin blog.csdn.net/u010687761/article/details/133200887
Recomendado
Clasificación