fundo
No Android 4.4 (KitKat), o Google tornou o acesso ao cartão SD bastante restrito.
A partir do Android Lollipop (5.0), os desenvolvedores podem usar uma nova API que pede ao usuário uma confirmação para permitir o acesso a pastas específicas, conforme escrito nesta postagem do Google-Groups .
O problema
A postagem direciona você a visitar dois sites:
Isso parece um exemplo interno (talvez a ser mostrado nas demonstrações da API mais tarde), mas é muito difícil entender o que está acontecendo.
Esta é a documentação oficial da nova API, mas não fornece detalhes suficientes sobre como usá-la.
Aqui está o que ele diz a você:
Se você realmente precisa de acesso total a uma subárvore inteira de documentos, comece lançando ACTION_OPEN_DOCUMENT_TREE para permitir que o usuário escolha um diretório. Em seguida, passe o getData () resultante para fromTreeUri (Context, Uri) para começar a trabalhar com a árvore selecionada pelo usuário.
Conforme você navega na árvore de instâncias de DocumentFile, você sempre pode usar getUri () para obter o Uri que representa o documento subjacente para aquele objeto, para uso com openInputStream (Uri), etc.
Para simplificar seu código em dispositivos que executam KITKAT ou anterior, você pode usar fromFile (File) que emula o comportamento de um DocumentsProvider.
As questões
Tenho algumas perguntas sobre a nova API:
- Como você realmente usa isso?
- De acordo com a postagem, o SO vai lembrar que o aplicativo recebeu permissão para acessar os arquivos / pastas. Como você verifica se consegue acessar os arquivos / pastas? Existe uma função que me retorna a lista de arquivos / pastas que posso acessar?
- Como você lida com esse problema no Kitkat? Faz parte da biblioteca de suporte?
- Existe uma tela de configurações no sistema operacional que mostra quais aplicativos têm acesso a quais arquivos / pastas?
- O que acontece se um aplicativo for instalado para vários usuários no mesmo dispositivo?
- Existe alguma outra documentação / tutorial sobre esta nova API?
- As permissões podem ser revogadas? Em caso afirmativo, há um intent sendo enviado ao aplicativo?
- Solicitar a permissão funcionaria recursivamente em uma pasta selecionada?
- Usar a permissão também permitiria ao usuário a chance de seleção múltipla por escolha do usuário? Ou o aplicativo precisa informar especificamente a intenção quais arquivos / pastas permitir?
- Existe uma maneira no emulador de experimentar a nova API? Quer dizer, ele tem partição de cartão SD, mas funciona como o armazenamento externo primário, então todo o acesso a ele já é concedido (usando uma permissão simples).
- O que acontece quando o usuário substitui o cartão SD por outro?
fonte
Respostas:
Muitas perguntas boas, vamos nos aprofundar. :)
como você usa isso?
Este é um ótimo tutorial para interagir com o Storage Access Framework no KitKat:
https://developer.android.com/guide/topics/providers/document-provider.html#client
A interação com as novas APIs no Lollipop é muito semelhante. Para solicitar que o usuário escolha uma árvore de diretório, você pode iniciar um intent como este:
Então, em onActivityResult (), você pode passar o Uri escolhido pelo usuário para a nova classe auxiliar DocumentFile. Aqui está um exemplo rápido que lista os arquivos no diretório escolhido e, em seguida, cria um novo arquivo:
O Uri retornado por
DocumentFile.getUri()
é flexível o suficiente para ser usado com várias APIs de plataformas diferentes. Por exemplo, você pode compartilhar usandoIntent.setData()
comIntent.FLAG_GRANT_READ_URI_PERMISSION
.Se você quiser acessar esse Uri do código nativo, pode chamar
ContentResolver.openFileDescriptor()
e usarParcelFileDescriptor.getFd()
oudetachFd()
para obter um inteiro descritor de arquivo POSIX tradicional.Como você verifica se consegue acessar os arquivos / pastas?
Por padrão, o Uris retornado por meio de intents do Storage Access Frameworks não persiste nas reinicializações. A plataforma "oferece" a capacidade de persistir a permissão, mas você ainda precisa "pegar" a permissão se quiser. Em nosso exemplo acima, você chamaria:
Você sempre pode descobrir a quais concessões persistentes seu aplicativo tem acesso por meio da
ContentResolver.getPersistedUriPermissions()
API. Se você não precisar mais acessar um Uri persistente, poderá liberá-lo comContentResolver.releasePersistableUriPermission()
.Isso está disponível no KitKat?
Não, não podemos adicionar retroativamente novas funcionalidades a versões mais antigas da plataforma.
Posso ver quais aplicativos têm acesso a arquivos / pastas?
Atualmente não há interface do usuário que mostra isso, mas você pode encontrar os detalhes na seção "Permissões de Uri concedidas" da
adb shell dumpsys activity providers
saída.O que acontece se um aplicativo for instalado para vários usuários no mesmo dispositivo?
As concessões de permissão de Uri são isoladas por usuário, assim como todas as outras funcionalidades da plataforma multiusuário. Ou seja, o mesmo aplicativo em execução com dois usuários diferentes não tem concessões de permissão Uri sobrepostas ou compartilhadas.
As permissões podem ser revogadas?
O DocumentProvider de apoio pode revogar a permissão a qualquer momento, como quando um documento baseado em nuvem é excluído. A maneira mais comum de descobrir essas permissões revogadas é quando elas desaparecem dos itens
ContentResolver.getPersistedUriPermissions()
mencionados acima.As permissões também são revogadas sempre que os dados do aplicativo são apagados para qualquer um dos aplicativos envolvidos na concessão.
Solicitar a permissão funcionaria recursivamente em uma pasta selecionada?
Sim, a
ACTION_OPEN_DOCUMENT_TREE
intenção oferece acesso recursivo a arquivos e diretórios existentes e recém-criados.Isso permite a seleção múltipla?
Sim, a seleção múltipla tem suporte desde KitKat, e você pode permitir definindo
EXTRA_ALLOW_MULTIPLE
ao iniciar seuACTION_OPEN_DOCUMENT
intent. Você pode usarIntent.setType()
ouEXTRA_MIME_TYPES
para restringir os tipos de arquivos que podem ser selecionados:http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT
Existe uma maneira no emulador de experimentar a nova API?
Sim, o dispositivo de armazenamento compartilhado principal deve aparecer no seletor, mesmo no emulador. Se seu aplicativo só usa o Access Storage Framework para acessar o armazenamento compartilhado, você não precisa mais as
READ/WRITE_EXTERNAL_STORAGE
permissões em tudo e pode removê-los ou usar oandroid:maxSdkVersion
recurso apenas solicitá-los em versões de plataforma mais velhos.O que acontece quando o usuário substitui o cartão SD por outro?
Quando a mídia física está envolvida, o UUID (como o número de série FAT) da mídia subjacente é sempre gravado no Uri retornado. O sistema usa isso para conectar você à mídia que o usuário selecionou originalmente, mesmo se o usuário trocar a mídia entre vários slots.
Se o usuário trocar em um segundo cartão, você precisará solicitar acesso ao novo cartão. Como o sistema se lembra das concessões por UUID, você continuará a ter acesso concedido anteriormente ao cartão original se o usuário o reinserir posteriormente.
http://en.wikipedia.org/wiki/Volume_serial_number
fonte
No meu projeto Android no Github, link abaixo, você pode encontrar o código de trabalho que permite escrever em extSdCard no Android 5. Ele assume que o usuário dá acesso a todo o cartão SD e, em seguida, permite que você escreva em qualquer lugar neste cartão. (Se você deseja ter acesso apenas a arquivos individuais, as coisas ficam mais fáceis.)
Snipplets de código principal
Acionando a estrutura de acesso ao armazenamento:
Lidando com a resposta do Storage Access Framework:
Obter um outputStream para um arquivo por meio do Storage Access Framework (fazendo uso do URL armazenado, supondo que este seja o URL da pasta raiz do cartão SD externo)
Isso usa os seguintes métodos auxiliares:
Referência ao código completo
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/fragments/SettingsFragment.java#L521
e
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java
fonte
File
254 vezes. Você pode imaginar consertar isso ?? O Android está se tornando um pesadelo para os desenvolvedores com sua total falta de compatibilidade com versões anteriores. Ainda não encontrei nenhum lugar onde explicassem porque o Google tomou todas essas decisões estúpidas em relação ao armazenamento externo. Alguns alegam "segurança", mas é claro que não faz sentido, pois qualquer aplicativo pode bagunçar o armazenamento interno. Meu palpite é tentar nos forçar a usar seus serviços em nuvem. Felizmente, o root resolve os problemas ... pelo menos para Android <6 ....É apenas uma resposta complementar.
Depois de criar um novo arquivo, pode ser necessário salvar seu local no banco de dados e lê-lo amanhã. Você pode ler recuperá-lo novamente usando este método:
fonte