Estou procurando uma maneira de compartilhar corretamente (não ABRIR) um arquivo interno com um aplicativo externo usando o FileProvider da biblioteca de suporte do Android .
Seguindo o exemplo nos documentos,
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.supportv4.my_files"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/my_paths" />
</provider>
e usando o ShareCompat para compartilhar um arquivo com outros aplicativos, da seguinte maneira:
ShareCompat.IntentBuilder.from(activity)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
não funciona, pois o FLAG_GRANT_READ_URI_PERMISSION concede apenas permissão para o Uri especificado na data
intenção, não o valor do EXTRA_STREAM
extra (conforme definido por setStream
).
Tentei comprometer a segurança definindo android:exported
como true
para o provedor, mas FileProvider
verifica internamente se ele próprio é exportado; nesse caso, gera uma exceção.
android
android-contentprovider
android-support-library
android-fileprovider
Randy Sugianto 'Yuku'
fonte
fonte
Respostas:
Usando
FileProvider
da biblioteca de suporte, você precisa conceder e revogar manualmente permissões (em tempo de execução) para outros aplicativos lerem Uri específico. Use Context.grantUriPermission e Context.revokeUriPermission métodos.Por exemplo:
Como último recurso, se você não puder fornecer o nome do pacote, poderá conceder a permissão a todos os aplicativos que possam lidar com intenções específicas:
Método alternativo de acordo com a documentação :
Btw. se necessário, você pode copiar a origem do FileProvider e alterar o
attachInfo
método para impedir que o provedor verifique se ele foi exportado.fonte
grantUriPermission
método, precisamos fornecer o nome do pacote do aplicativo ao qual queremos conceder a permissão. No entanto, ao compartilhar, geralmente não sabemos qual aplicativo é o destino de compartilhamento.Exemplo de código totalmente funcional como compartilhar arquivos da pasta interna do aplicativo. Testado no Android 7 e Android 5.
AndroidManifest.xml
xml / provider_paths
Código em si
fonte
ShareCompat.IntentBuilder
permissão de leitura e URI finalmente fez isso por mim.FileProvider
que funciona. As outras respostas entendem errado o manuseio da intenção (elas não a usamShareCompat.IntentBuilder
) e essa intenção não pode ser aberta por aplicativos externos de maneira significativa. Passei literalmente a maior parte do dia nessa bobagem até finalmente encontrar sua resposta.Esta solução funciona para mim desde o OS 4.4. Para fazê-lo funcionar em todos os dispositivos, adicionei uma solução alternativa para dispositivos mais antigos. Isso garante que sempre seja usada a solução mais segura.
Manifest.xml:
file_paths.xml:
Java:
A permissão é revogada com revokeFileReadPermission () nos métodos onResume e onDestroy () do Fragmento ou da Atividade.
fonte
file
não mudará deonResume
paraonDestroy
?Como Phil disse em seu comentário sobre a pergunta original, isso é único e não há outras informações sobre SO no google, pensei em compartilhar meus resultados:
No meu aplicativo, o FileProvider funcionou imediatamente para compartilhar arquivos usando a intenção de compartilhar. Não havia nenhuma configuração ou código especial necessário, além disso para configurar o FileProvider. No manifest.xml, coloquei:
Em my_paths.xml, tenho:
No meu código eu tenho:
E posso compartilhar meu armazenamento de arquivos no armazenamento privado de meus aplicativos com aplicativos como o Gmail e o Google Drive sem nenhum problema.
fonte
Tanto quanto posso dizer, isso só funcionará em versões mais recentes do Android, então você provavelmente precisará descobrir uma maneira diferente de fazer isso. Esta solução funciona para mim no 4.4, mas não no 4.0 ou 2.3.3, portanto, não será uma maneira útil de compartilhar conteúdo para um aplicativo que deve ser executado em qualquer dispositivo Android.
No manifest.xml:
Tome nota cuidadosa de como você especifica as autoridades. Você deve especificar a atividade a partir da qual você criará o URI e iniciará a intenção de compartilhamento; nesse caso, a atividade será chamada SharingActivity. Este requisito não é óbvio nos documentos do Google!
file_paths.xml:
Cuidado ao especificar o caminho. O padrão acima é a raiz do seu armazenamento interno privado.
Em SharingActivity.java:
Neste exemplo, estamos compartilhando uma imagem JPEG.
Finalmente, é provavelmente uma boa idéia garantir que você salvou o arquivo corretamente e que você pode acessá-lo com algo assim:
fonte
No meu aplicativo, o FileProvider funciona muito bem e posso anexar arquivos internos armazenados no diretório de arquivos a clientes de e-mail como Gmail, Yahoo etc.
No meu manifesto, como mencionado na documentação do Android, eu coloquei:
E como meus arquivos foram armazenados no diretório de arquivos raiz, os filepaths.xml foram os seguintes:
Agora no código:
Isso funcionou para mim. Espero que isso ajude :)
fonte
Se você obtiver uma imagem da câmera, nenhuma dessas soluções funcionará no Android 4.4. Nesse caso, é melhor verificar as versões.
fonte
apenas para melhorar a resposta dada acima: se você estiver recebendo o NullPointerEx:
você também pode usar getApplicationContext () sem contexto
fonte
Quero compartilhar algo que nos bloqueou por alguns dias: o código do provedor de arquivo DEVE ser inserido entre as tags do aplicativo, não depois dele. Pode ser trivial, mas nunca especificado, e pensei que poderia ter ajudado alguém! (obrigado novamente a piolo94)
fonte