Android 7.0 以后,Android系统不再允许 Intent 携带 "file:// “开头的uri,会抛出信息暴露的异常。
发送者需要在 AndroidManifest.xml 中添加一个 FileProvider:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
然后定义一个 file_paths.xml
<paths>
<external-path
name="external_storage_root"
path="." />
</paths>
在请求查看文件时,指定 uri, 填充文件的mime信息。
File file = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/test.jpg";
String mime = "image/jpeg";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//判断是否是AndroidN以及更高的版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", file);
intent.setDataAndType(contentUri, mime);
} else {
intent.setDataAndType(Uri.fromFile(file), mime);
}
try {
startActivity(intent);
}catch (Exception e){
}
这个方式会调用系统的选择框列出支持的应用。但是这时候传入的文件,好多应用都打不开,提示”请求资源失败“啥的。
原因在于,这些应用遇到 content:// 开头的 Uri 资源,首先就去 MediaStore 查询这个 Uri,因为这是应用私有Uri,自然查不到,就返回这个错误。
解决办法,就是让被调用的应用使用 MediaStore查不到后,采用 ContentResolver 的 OpenFileDescriptor 再尝试打开,当然自己的应用可以这么干,别家的只能期待他们这么做。
https://developer.android.google.cn/reference/android/content/ContentResolver.html#openFileDescriptor(android.net.Uri,%20java.lang.String)
最后一个办法就是,把发送者的 targetSdkVersion 设为 23 或者更低,然后直接传递 file://开头的Uri,Android系统就不报错了,应该是兼容旧版。而大部分第三方应用还是兼容支持file://开头的Uri的,只要你能传递给他。那么这样就解决问题了~~