Antes do KitKat (ou antes da nova Galeria), Intent.ACTION_GET_CONTENT
um URI retornado como este
conteúdo: // media / external / images / media / 3951.
O uso de ContentResolver
e query for
MediaStore.Images.Media.DATA
retornou o URL do arquivo.
No KitKat, no entanto, a Galeria retorna um URI (via "Último") como este:
conteúdo: //com.android.providers.media.documents/document/image: 3951
Como eu manejo isso?
android
android-intent
android-gallery
android-contentresolver
Michael Greifeneder
fonte
fonte
Uri
deve ser aberto como um fluxo viaContentResolver
. Há muito tempo fico nervoso com aplicativos que assumem que umcontent://
Uri
que representa um arquivo sempre pode ser convertido em umFile
.InputStream
sobre oContentResolver
para um local pré-designado por isso tem um nome de arquivo conhecida. No entanto, isso parece um desperdício para mim. Alguma outra sugestão?InputStream
over JNI? Infelizmente, não existem muitas opções para você.InputStream
vez de um arquivo (o que é ótimo). Somente a leitura de tags EXIF é um pouco complicada e requer a biblioteca de Drew Noakes . Muito obrigado pelos seus comentários.Respostas:
Tente o seguinte:
Provavelmente precisa
para
fonte
Isso não requer permissões especiais e funciona com o Storage Access Framework, bem como o
ContentProvider
padrão não oficial (caminho do arquivo no_data
campo).Veja uma versão atualizada deste método aqui .
fonte
Authority: com.google.android.apps.docs.storage
eSegments: [document, acc=1;doc=667]
. Não tenho certeza, mas suponha que odoc
valor seja oUri
ID que você possa consultar. Provavelmente, você precisará configurar permissões conforme detalhado em "Autorizar seu aplicativo no Android" aqui: developers.google.com/drive/integrate-android-ui . Atualize aqui se você descobrir._data
não funcionaria quando o ContentProvider não o suporta. Recomenda-se seguir as instruções do @CommonsWare e não usar mais o caminho completo do arquivo, pois pode ser um arquivo na nuvem do Dropbox em vez de um arquivo real.Teve o mesmo problema, tentei a solução acima, mas, embora funcionasse geralmente, por algum motivo eu estava obtendo negação de permissão no provedor de conteúdo Uri para algumas imagens, embora eu tivesse a
android.permission.MANAGE_DOCUMENTS
permissão adicionada corretamente.De qualquer forma, encontrou outra solução que é forçar a abertura da galeria de imagens em vez dos documentos do KITKAT visualizados com:
e carregue a imagem:
EDITAR
ACTION_OPEN_DOCUMENT
pode exigir que você persista sinalizadores de permissões etc. e geralmente resulta em Exceções de segurança ...Outra solução é usar o
ACTION_GET_CONTENT
combinado com oc.getContentResolver().openInputStream(selectedImageURI)
qual funcionará tanto no pré-KK quanto no KK. Kitkat utilizará a nova exibição de documentos e essa solução funcionará com todos os aplicativos como Fotos, Galeria, Explorador de Arquivos, Dropbox, Google Drive, etc ...) mas lembre-se de que ao usar esta solução, é necessário criar uma imagemonActivityResult()
e armazená-la no Cartão SD, por exemplo. A recriação dessa imagem do uri salvo no próximo lançamento do aplicativo geraria Exceção de Segurança no resolvedor de conteúdo, mesmo quando você adiciona sinalizadores de permissão, conforme descrito nos documentos da API do Google (foi o que aconteceu quando fiz alguns testes)Além disso, as Diretrizes da API do desenvolvedor do Android sugerem:
fonte
Intent.ACTION_GET_CONTENT
. De qualquer forma, mantive oIntent.createChooser()
invólucro no novoIntent
, para permitir que o usuário escolhesse o aplicativo para navegação e trabalhei como esperado. Alguém pode ver os inconvenientes desta solução?Assim como o Commonsware mencionou, você não deve presumir que o fluxo obtido
ContentResolver
é convertível em arquivo.O que você realmente deve fazer é abrir a
InputStream
partir doContentProvider
e criar um bitmap a partir dele. E funciona também nas versões 4.4 e anteriores, sem necessidade de reflexão.Obviamente, se você manipular imagens grandes, carregue-as com o seguinte
inSampleSize
: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . Mas esse é outro tópico.fonte
Acredito que as respostas já postadas devem levar as pessoas na direção certa. No entanto, aqui está o que eu fiz que fazia sentido para o código legado que eu estava atualizando. O código legado estava usando o URI da galeria para alterar e salvar as imagens.
Antes do 4.4 (e do Google Drive), os URIs teriam a seguinte aparência: conteúdo: // media / external / images / media / 41
Conforme declarado na pergunta, eles costumam se parecer com isso: content: //com.android.providers.media.documents/document/image: 3951
Como eu precisava salvar imagens e não perturbar o código já existente, copiei o URI da galeria para a pasta de dados do aplicativo. Em seguida, originou um novo URI do arquivo de imagem salvo na pasta de dados.
Aqui está a ideia:
Nota - copyAndClose () apenas arquiva E / S para copiar InputStream em um FileOutputStream. O código não é publicado.
fonte
Só queria dizer que essa resposta é brilhante e eu a uso há muito tempo sem problemas. Mas, há algum tempo, deparei com um problema em que o DownloadsProvider retorna URIs no formato
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf
e, portanto, o aplicativo sofre uma falhaNumberFormatException
porque é impossível analisar seus segmentos de uri por muito tempo. Mas oraw:
segmento contém um URI direto que pode ser usado para recuperar um arquivo referenciado. Então, eu o corrigi substituindo oisDownloadsDocument(uri)
if
conteúdo pelo seguinte:fonte
Combinei várias respostas em uma solução funcional que resulta no caminho do arquivo
O tipo MIME é irrelevante para o propósito de exemplo.
Resultado de manipulação
FilePickUtils
fonte
Questão
Como obter um caminho de arquivo real de um URI
Responda
Que eu saiba, não precisamos obter o caminho do arquivo de um URI porque, na maioria dos casos, podemos usar diretamente o URI para realizar nosso trabalho (como 1. obter bitmap 2. Enviar um arquivo para o servidor etc.) .)
1. Enviando para o servidor
Podemos enviar o arquivo diretamente para o servidor usando apenas o URI.
Usando o URI, podemos obter o InputStream, que podemos enviar diretamente para o servidor usando o MultiPartEntity.
Exemplo
2. Obtendo um BitMap de um URI
Se o URI estiver apontando para a imagem, obteremos bitmap, caso contrário nulo:
Comentários
Referência
fonte
Esta biblioteca Android lida com as alterações de caso no KitKat (incluindo as versões anteriores - 2.1+):
https://github.com/iPaulPro/aFileChooser
Use o
String path = FileUtils.getPath(context, uri)
para converter o Uri retornado em uma sequência de caminho utilizável em todas as versões do sistema operacional. Veja mais sobre isso aqui: https://stackoverflow.com/a/20559175/860488fonte
Para aqueles que ainda estão usando o código de @Paul Burke com o Android SDK versão 23 e superior, se o seu projeto encontrou o erro dizendo que está faltando EXTERNAL_PERMISSION e você tem certeza de que já adicionou permissão de usuário no arquivo AndroidManifest.xml. Isso ocorre na API 23 do Android ou superior e o Google torna necessário garantir a permissão novamente enquanto você executa a ação para acessar o arquivo em tempo de execução.
Isso significa: Se a sua versão do SDK for 23 ou superior, você precisará da permissão READ & WRITE enquanto seleciona o arquivo de imagem e deseja saber o URI dele.
E a seguir está o meu código, além da solução de Paul Burke. Eu adiciono esse código e meu projeto começa a funcionar bem.
E em sua atividade e fragmento em que você está solicitando o URI:
No meu caso, CompatUtils.java é onde eu defino o método confirmStoragePermissions (como tipo estático, para que eu possa chamá-lo em outra atividade).
Além disso, deve fazer mais sentido se você fizer um estado if primeiro para ver se a versão atual do SDK está acima de 23 ou não antes de chamar o método confirmStoragePermissions.
fonte
Esta resposta é de m3n0R na pergunta android get real path by Uri.getPath () e não reivindico crédito. Eu apenas pensei que pessoas que ainda não haviam resolvido esse problema poderiam usá-lo.
fonte
cursor.getString(idx);
Tente evitar o uso do método takePersistableUriPermission, pois isso gerou uma exceção de tempo de execução para mim. / ** * Selecione da galeria. * /
OnActivity para resultado para manipular os dados da imagem:
@Override void protegido onActivityResult (int requestCode, int resultCode, Intent data) {
fonte
Se alguém estiver interessado, eu fiz uma versão funcional do Kotlin para
ACTION_GET_CONTENT
:fonte
Eu tentei várias respostas aqui e acho que tenho uma solução que funcionará sempre e gerencia permissões também.
Baseia-se na solução inteligente da LEO. Esta postagem deve conter todo o código necessário para que isso funcione e em qualquer telefone e versão do Android;)
Para poder escolher um arquivo de um cartão SD, você precisará disso em seu manifesto:
Constantes:
Verifique a permissão e launchImagePick, se possível
Resposta de permissão
Gerenciar resposta de permissão
Iniciar seleção de imagem
Gerenciar resposta de seleção de imagem
Isso é tudo, pessoal; isso funciona para mim em todos os telefones que tenho.
fonte
Este é um truque total, mas aqui está o que eu fiz ...
Portanto, durante a configuração do DocumentsProvider , observei que o código de exemplo (na
getDocIdForFile
linha 450) gera um ID exclusivo para um documento selecionado com base no caminho (exclusivo) do arquivo em relação à raiz especificada (ou seja, o que você definiumBaseDir
na linha 96).Portanto, o URI acaba parecendo algo como:
content://com.example.provider/document/root:path/to/the/file
Como dizem os documentos, ele assume apenas uma única raiz (no meu caso,
Environment.getExternalStorageDirectory()
mas você pode usar em outro lugar ... então ele pega o caminho do arquivo, começando na raiz, e o torna o ID exclusivo, precedendo "root:
". Então eu pode determinar o caminho eliminando a"/document/root:
"parte" de uri.getPath (), criando um caminho de arquivo real fazendo algo como isto:Eu sei. É vergonhoso, mas funcionou. Novamente, isso depende de você usar seu próprio provedor de documentos no seu aplicativo para gerar a ID do documento.
(Além disso, há uma maneira melhor de construir o caminho que não assume "/" é o separador de caminhos etc. Mas você entendeu.)
fonte
file://
intenções de um seletor de arquivos externo, você também poderá verificar a autoridade, como no exemplo acima, para garantir que seja do seu provedor personalizado e, se for o caso, poderá use também o caminho para "forjar" uma novafile://
intenção usando o caminho que você extraiuStartActivity()
e deixe seu aplicativo buscá-lo. Eu sei, terrível.Isso funcionou bem pra mim:
fonte
Com base na resposta de Paul Burke, enfrentei muitos problemas ao resolver o caminho URI do cartão SD externo, pois a maioria das funções "internas" sugeridas retornam caminhos que não são resolvidos nos arquivos.
No entanto, esta é a minha abordagem de seu // TODO manipular volumes não primários .
Observe que depende da hierarquia que pode ser diferente em todos os fabricantes de telefones - ainda não os testei (funcionou até agora no Xperia Z3 API 23 e no Samsung Galaxy A3 API 23).
Confirme se não apresenta um bom desempenho em outro local.
fonte
A resposta de @paul burke funciona bem para as fotos da câmera e da galeria para o nível 19 da API e acima, mas não funciona se o SDK mínimo do seu projeto Android estiver definido como abaixo de 19 e algumas respostas acima não funcionarem para a galeria e Câmera. Bem, eu modifiquei o código do @paul burke, que funciona para o nível da API abaixo de 19. Abaixo está o código.
fonte
A resposta para sua pergunta é que você precisa ter permissões. Digite o seguinte código no seu arquivo manifest.xml:
Funcionou para mim ...
fonte