O aplicativo está travando quando estou tentando abrir um arquivo. Funciona abaixo do Android Nougat, mas no Android Nougat ele trava. Ele só trava quando tento abrir um arquivo do cartão SD, não da partição do sistema. Algum problema de permissão?
Código de amostra:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Registro:
android.os.FileUriExposedException: file: ///storage/emulated/0/test.txt exposto além do aplicativo por meio de Intent.getData ()
Editar:
Ao segmentar o Android Nougat, os file://
URIs não são mais permitidos. Em content://
vez disso, devemos usar URIs. No entanto, meu aplicativo precisa abrir arquivos nos diretórios raiz. Alguma ideia?
android
android-file
android-7.0-nougat
Thomas Vos
fonte
fonte
Respostas:
Se for o seu caso
targetSdkVersion >= 24
, precisamos usar aFileProvider
classe para conceder acesso ao arquivo ou pasta específico para torná-los acessíveis para outros aplicativos. Criamos nossa própria classe de herançaFileProvider
para garantir que o FileProvider não entre em conflito com o FileProviders declarado nas dependências importadas, conforme descrito aqui .Etapas para substituir o
file://
URI pelocontent://
URI:Adicionar uma classe estendida
FileProvider
Adicione uma
<provider>
tag FileProvider na tagAndroidManifest.xml
under<application>
. Especifique uma autoridade exclusiva para oandroid:authorities
atributo para evitar conflitos, dependências importadas podem especificar${applicationId}.provider
e outras autoridades comumente usadas.provider_paths.xml
arquivo nares/xml
pasta Pode ser necessário criar uma pasta se ela não existir. O conteúdo do arquivo é mostrado abaixo. Ele descreve que gostaríamos de compartilhar o acesso ao armazenamento externo na pasta raiz(path=".")
com o nome external_files .A etapa final é alterar a linha de código abaixo em
para
Editar: se você estiver usando a intenção de abrir o arquivo, o sistema poderá ser necessário adicionar a seguinte linha de código:
Consulte, código completo e solução foram explicados aqui.
fonte
(Build.VERSION.SDK_INT > M)
condição é inútil.FileProvider
deve ser estendido somente se você deseja substituir qualquer comportamento padrão; caso contrário, useandroid:name="android.support.v4.content.FileProvider"
. Consulte developer.android.com/reference/android/support/v4/content/…Além da solução usando o
FileProvider
, há outra maneira de contornar isso. Basta colocarno
Application.onCreate()
. Dessa maneira, a VM ignora aURI
exposição do arquivo .Método
ativa a verificação de exposição do arquivo, que também é o comportamento padrão se não configurarmos um VmPolicy.
Eu encontrei um problema que, se eu usar um
content://
URI
para enviar algo, alguns aplicativos simplesmente não conseguem entender. E o downgrade datarget SDK
versão não é permitido. Nesse caso, minha solução é útil.Atualizar:
Conforme mencionado no comentário, StrictMode é uma ferramenta de diagnóstico e não deve ser usada para esse problema. Quando publiquei esta resposta há um ano, muitos aplicativos só podem receber uris de arquivos. Eles apenas travam quando eu tentei enviar um uri do FileProvider para eles. Isso foi corrigido na maioria dos aplicativos agora; portanto, devemos usar a solução FileProvider.
fonte
VmPolicy
.StrictMode.enableDefaults();
, que eu executo apenas em minhas compilações de desenvolvimento evita que essa falha aconteça - agora eu tenho um aplicativo de produção que falha, mas não falha quando está em desenvolvimento. Então, basicamente, ativar uma ferramenta de diagnóstico aqui oculta um problema sério. Obrigado @hqzxzwb por me ajudar a desmistificar isso.Se
targetSdkVersion
for maior que 24 , o FileProvider é usado para conceder acesso.Crie um arquivo xml (Caminho: res \ xml) provider_paths.xml
Adicionar um provedor no AndroidManifest.xml
Se você estiver usando o androidx , o caminho do FileProvider deve ser:
e substitua
para
Editar: enquanto você estiver incluindo o URI,
Intent
adicione uma linha abaixo:e você está pronto para ir. Espero que ajude.
fonte
Se seu aplicativo tiver como alvo a API 24+ e você ainda quiser / precisar usar file: // intents, poderá usar a maneira hacky para desativar a verificação de tempo de execução:
O método
StrictMode.disableDeathOnFileUriExposure
está oculto e documentado como:O problema é que meu aplicativo não é coxo, mas não quer ser aleijado usando content: // intents que não são compreendidos por muitos aplicativos por aí. Por exemplo, abrir arquivo mp3 com o esquema content: // oferece muito menos aplicativos do que abrir o mesmo sobre o arquivo: // esquema. Não quero pagar por falhas de design do Google limitando a funcionalidade do meu aplicativo.
O Google quer que os desenvolvedores usem o esquema de conteúdo, mas o sistema não está preparado para isso. Durante anos, os aplicativos foram feitos para usar Arquivos e não "conteúdo", os arquivos podem ser editados e salvos novamente, enquanto os arquivos veiculados no esquema de conteúdo não podem ser (podem eles?).
fonte
ContentResolver
tem ambosopenInputStream()
eopenOutputStream()
. Uma maneira menos invasiva de fazer isso é configurar você mesmo as regras da VM e não ativar afile
Uri
regra.Se você
targetSdkVersion
tem 24 anos ou mais, não é possível usarfile:
Uri
valores nosIntents
dispositivos Android 7.0 ou superior .Suas escolhas são:
Deixe cair
targetSdkVersion
para 23 ou menos, ouColoque seu conteúdo no armazenamento interno e use-o
FileProvider
para disponibilizá-lo seletivamente para outros aplicativosPor exemplo:
( deste projeto de amostra )
fonte
/system
partição? Todo aplicativo deve poder acessar esta partição sem raiz./system
ser legível pelo mundo. Dito isto, meu palpite é que você ainda receberá essa exceção. Eu suspeito que eles estão apenas verificando o esquema e não estão tentando determinar se o arquivo realmente é legível pelo mundo. No entanto,FileProvider
não o ajudará, pois você não pode ensiná-lo a servir/system
. Você pode criar uma estratégia personalizada para mimStreamProvider
, ou criar sua própriaContentProvider
, para superar o problema./data
,/system
), por causa dessa "boa mudança".Primeiro, você precisa adicionar um provedor ao seu AndroidManifest
agora crie um arquivo na pasta de recursos xml (se estiver usando o android studio, você pode pressionar Alt + Enter após destacar caminhos_do_arquivo e selecionar criar uma opção de recurso xml)
Em seguida, no arquivo file_paths, insira
Este exemplo é para caminho externo, você pode consultar aqui para mais opções. Isso permitirá que você compartilhe arquivos que estão nessa pasta e em sua subpasta.
Agora tudo o que resta é criar a intenção da seguinte maneira:
EDIT : eu adicionei a pasta raiz do cartão sd no file_paths. Eu testei esse código e ele funciona.
fonte
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
Além disso, recomendo a quem procura respostas para ler primeiro o FileProvider e entender o que você está lidando aqui com permissões de arquivo no Android N e acima. Existem opções para armazenamento interno versus armazenamento externo e também para caminhos de arquivos regulares e caminhos de cache.java.lang.IllegalArgumentException: Failed to find configured root ...
e a única coisa que funcionou foi<files-path path="." name="files_root" />
no arquivo xml, em vez de<external-path ...
. Meu arquivo foi salvo no armazenamento interno.A resposta do @palash k está correta e funcionou para arquivos de armazenamento interno, mas, no meu caso, também quero abrir arquivos do armazenamento externo, meu aplicativo travou quando o arquivo foi aberto do armazenamento externo, como sdcard e usb, mas consegui resolver o problema modificando provider_paths.xml da resposta aceita
altere o provider_paths.xml como abaixo
e na classe java (nenhuma alteração, pois a resposta aceita é apenas uma pequena edição)
Isso me ajuda a corrigir a falha de arquivos de armazenamentos externos. Espero que isso ajude alguém com o mesmo problema que o meu :)
fonte
<root-path
favor? Está funcionando.<external-path path="Android/data/${applicationId}/" name="files_root" />
não teve efeito para arquivos abertos do armazenamento externo.Android/data/${applicationId}/
em SDcard.Minha solução foi 'Uri.parse' o caminho do arquivo como String, em vez de usar Uri.fromFile ().
Parece que fromFile () usa um ponteiro de arquivo, que suponho que pode ser inseguro quando endereços de memória são expostos a todos os aplicativos. Mas Um caminho de arquivo String nunca prejudica ninguém, por isso funciona sem lançar FileUriExposedException.
Testado nos níveis de API 9 a 27! Abre com êxito o arquivo de texto para edição em outro aplicativo. Não requer o FileProvider, nem a Biblioteca de Suporte do Android.
fonte
Basta colar o código abaixo na atividade onCreate ()
Ele ignorará a exposição ao URI
fonte
Basta colar o código abaixo na atividade
onCreate()
.Ele ignorará a exposição ao URI.
Happy coding :-)
fonte
Usar o fileProvider é o caminho a percorrer. Mas você pode usar esta solução alternativa simples:
substituir:
de
fonte
Eu usei a resposta de Palash dada acima, mas estava um pouco incompleta, tive que fornecer permissão como esta
fonte
Basta colar o código abaixo na atividade onCreate ()
Ele ignorará a exposição ao URI
fonte
adicione essas duas linhas no onCreate
Método de compartilhamento
fonte
Aqui está a minha solução:
no Manifest.xml
em res / xml / provider_paths.xml
no meu fragmento eu tenho o próximo código:
É tudo o que você precisa.
Também não precisa criar
Eu testo no Android 5.0, 6.0 e Android 9.0 e é um trabalho bem-sucedido.
fonte
Para baixar pdf do servidor, adicione o código abaixo na sua classe de serviço. Espero que isso seja útil para você.
E sim, não esqueça de adicionar permissões e provedor no seu manifesto.
fonte
@xml/provider_paths
?Não sei por que, fiz tudo exatamente igual ao Pkosta ( https://stackoverflow.com/a/38858040 ), mas continuava recebendo erro:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
Eu perdi horas nessa questão. O culpado? Kotlin.
intent
estava realmente definindo emgetIntent().addFlags
vez de operar no meu recém-declarado playIntent.fonte
Eu coloquei esse método para que o caminho imageuri entre facilmente no conteúdo.
fonte
Existem três etapas principais aqui, conforme mencionado abaixo
Etapa 1: Entrada do manifesto
Etapa 2: criar o arquivo XML res / xml / provider_paths.xml
Etapa 3: alterações de código
fonte
Sei que essa é uma pergunta bastante antiga, mas essa resposta é para futuros telespectadores. Então, eu encontrei um problema semelhante e, depois de pesquisar, encontrei uma alternativa para essa abordagem.
Sua intenção aqui, por exemplo: Para visualizar sua imagem do seu caminho no Kotlin
Função principal abaixo
Da mesma forma, em vez de uma imagem, você pode usar qualquer outro formato de arquivo, como pdf, e no meu caso, funcionou bem
fonte
Passei quase um dia tentando descobrir por que estava recebendo essa exceção. Após muita luta, essa configuração funcionou perfeitamente ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Intenção em si
Eu explico todo o processo aqui .
fonte
https://stackoverflow.com/a/38858040/395097, esta resposta está completa.
Esta resposta é para: você já tem um aplicativo com segmentação abaixo de 24 e agora está atualizando para targetSDKVersion> = 24.
No Android N, apenas o URL do arquivo exposto ao aplicativo de terceiros é alterado. (Não da maneira que estávamos usando antes). Altere apenas os lugares em que você está compartilhando o caminho com o aplicativo de terceiros (câmera no meu caso)
Em nosso aplicativo, estávamos enviando uri para o aplicativo Câmera. Nesse local, esperamos que o aplicativo da câmera armazene a imagem capturada.
Agora, temos 2 uri diferentes para o mesmo arquivo. O nº 1 é compartilhado com o aplicativo Câmera. Se a intenção da câmera for bem sucedida, podemos acessar a imagem do item 2.
Espero que isto ajude.
fonte
Xamarin.Android
Nota: O caminho xml / provider_paths.xml (.axml) não pôde ser resolvido, mesmo depois de criar a pasta xml em Resources (talvez ela possa ser colocada em um local existente como Values , não tentei), por isso recorri a isso que funciona por enquanto. Os testes mostraram que ele só precisa ser chamado uma vez por execução do aplicativo (o que faz sentido, pois altera o estado operacional da VM do host).
Nota: o xml precisa ser capitalizado, portanto, Resources / Xml / provider_paths.xml
fonte
A resposta da @Pkosta é uma maneira de fazer isso.
Além de usar
FileProvider
, você também pode inserir o arquivoMediaStore
(especialmente para arquivos de imagem e vídeo), porque os arquivos no MediaStore são acessíveis a todos os aplicativos:Por exemplo, você pode inserir um arquivo de vídeo no MediaStore assim:
contentUri
é comocontent://media/external/video/media/183473
, que pode ser passado diretamente paraIntent.putExtra
:Isso funciona para mim e economiza os aborrecimentos de usar
FileProvider
.fonte
Simplesmente deixe-o ignorar a exposição do URI ... Adicione-o após a criação
fonte
Experimente esta solução
COLOCAR ESTAS PERMISSÕES EM MANIFESTO
INTENÇÃO DE CAPTURAR IMAGEM
OBTENHA IMAGEM CAPTURADA EM RESULTADO DA ATIVIDADE
MÉTODO PARA OBTER URI DE IMAGEM
fonte
No meu caso, me livrei da exceção substituindo
SetDataAndType
por justSetData
.fonte