android 7.0以后
为了提高私有目录的安全性,防止应用信息的泄漏,从 Android 7.0 开始,应用私有目录的访问权限被做限制。具体表现为,开发人员不能够再简单地通过 file:// URI 访问其他应用的私有目录文件或者让其他应用访问自己的私有目录文件。
作为四大组件之一的 ContentProvider,一直扮演着应用间共享资源的角色。这里我们要使用到的 FileProvider,就是 ContentProvider 的一个特殊子类,帮助我们将访问受限的 file:// URI 转化为可以授权共享的 content:// URI。
第一步 注册一个provider
AandroidMainfest.xml 中添加:
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
注意name跟以前版本的区分,以前是 “android.support.v4.content.FileProvider” ,现在换成了 “androidx.core.content.FileProvider” 。
第二步 设置共享目录
配合上面的 android:resource="@xml/provider_paths" ,我们在 res/xml 目录下新建一个 provider_paths.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="Download/" name= "external_images" />
</paths>
路径可以是一个或者多个:
- files-path:内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;
- cache-path:内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;
- external-path:外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;
- external-files-path:外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;
- external-cache-path:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();
每个子元素都拥有 name 和 path 两个属性。
- path 属性用于指定当前子元素所代表目录下需要共享的子目录名称。注意:path 属性值不能使用具体的独立文件名,只能是目录名。
- name 属性用于给 path 属性所指定的子目录名称取一个别名。后续生成 content:// URI 时,会使用这个别名代替真实目录名。这样做的目的,很显然是为了提高安全性。
如果我们需要分享的文件位于同级别目录下不同的子目录中,就需要添加多个子元素逐一指定要分享的文件目录,或者共享他们通用的父目录也是可行的。
第三部 获取url,选择type分享
private share(String downloadFile,Context context){
Intent fileIntent = new Intent(Intent.ACTION_SEND);
fileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//给临时权限
fileIntent.setType(getMimeType(downloadFile));//根据文件类型设定type
//Android7.0版本以上使用FileProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fileIntent.putExtra(Intent.EXTRA_STREAM,
FileProvider.getUriForFile(context, getPackageName() +".provider",
new File(downloadFile)));
}else {
fileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(downloadFile));
}
startActivity(Intent.createChooser(fileIntent, "Share"));
}
private String getMimeType(String filePath) {
String ext = MimeTypeMap.getFileExtensionFromUrl(filePath);
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext);
}
以前直接用绝对地址的 url 就可以,Android 7 以后就需要用到 FileProvider来分享,用FileProvider.getUriForFile()方法获取 Content URI,第二个参数就是 Manifest 文件中注册 FileProvider 时设置的 authorities 属性值,第三个参数为要共享的文件,并且这个文件一定位于第二步我们在 path 文件中添加的子目录里面。同时里面还包含设置分享文件类型的小技巧,根据获取到的url实时区分文件的种类。