使用content://
替代file://
,主要需要FileProvider的支持,而因为FileProvider是ContentProvider的子类,所以需要在AndroidManifest.xml中注册;而又因为需要对真实的filepath进行映射,所以需要编写一个xml文档,用于描述可使用的文件夹目录,以及通过name去映射该文件夹目录。
对于权限,有两种方式:
- 方式一为Intent.addFlags,该方式主要用于针对intent.setData,setDataAndType以及setClipData相关方式传递uri的。
- 方式二为grantUriPermission来进行授权
相比来说方式二较为麻烦,因为需要指定目标应用包名,很多时候并不清楚,所以需要通过PackageManager进行查找到所有匹配的应用,全部进行授权。不过更为稳妥~
方式一较为简单,对于intent.setData,setDataAndType正常使用即可,但是对于setClipData,由于5.0前后Intent#migrateExtraStreamToClipData
,代码发生变化,需要注意
快速完成适配
(1)新建一个module
创建一个library
的module,在其AndroidManifest.xml中完成FileProvider的注册,代码编写为:
-
<application>
-
<provider
-
android:name="android.support.v4.content.FileProvider"
-
android:authorities="${applicationId}.android7.fileprovider"
-
android:exported="false"
-
android:grantUriPermissions="true">
-
<meta-data
-
android:name="android.support.FILE_PROVIDER_PATHS"
-
android:resource="@xml/file_paths" />
-
</provider>
-
</application>
注意一点,android:authorities
不要写死,因为该library最终可能会让多个项目引用,而android:authorities
是不可以重复的,如果两个app中定义了相同的,则后者无法安装到手机中(authority conflict)。
同样的的编写file_paths~
-
<?xml version="1.0" encoding="utf-8"?>
-
<paths xmlns:android="http://schemas.android.com/apk/res/android">
-
<root-path
-
name="root"
-
path="" />
-
<files-path
-
name="files"
-
path="" />
-
<cache-path
-
name="cache"
-
path="" />
-
<external-path
-
name="external"
-
path="" />
-
<external-files-path
-
name="external_file_path"
-
path="" />
-
<external-cache-path
-
name="external_cache_path"
-
path="" />
-
</paths>
最后再编写一个辅助类,例如:
-
public class FileProvider7 {
-
public static Uri getUriForFile(Context context, File file) {
-
Uri fileUri = null;
-
if (Build.VERSION.SDK_INT >= 24) {
-
fileUri = getUriForFile24(context, file);
-
} else {
-
fileUri = Uri.fromFile(file);
-
}
-
return fileUri;
-
}
-
public static Uri getUriForFile24(Context context, File file) {
-
Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(context,
-
context.getPackageName() + ".android7.fileprovider",
-
file);
-
return fileUri;
-
}
-
public static void setIntentDataAndType(Context context,
-
Intent intent,
-
String type,
-
File file,
-
boolean writeAble) {
-
if (Build.VERSION.SDK_INT >= 24) {
-
intent.setDataAndType(getUriForFile(context, file), type);
-
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
if (writeAble) {
-
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
}
-
} else {
-
intent.setDataAndType(Uri.fromFile(file), type);
-
}
-
}
-
}
可以根据自己的需求添加方法。
好了,这样我们的一个小库就写好了~~
(2)使用
如果哪个项目需要适配7.0,那么只需要这样引用这个库,然后只需要改动一行代码即可完成适配啦,例如:
拍照
-
public void takePhotoNoCompress(View view) {
-
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
-
String filename = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA)
-
.format(new Date()) + ".png";
-
File file = new File(Environment.getExternalStorageDirectory(), filename);
-
mCurrentPhotoPath = file.getAbsolutePath();
-
Uri fileUri = FileProvider7.getUriForFile(this, file);
-
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
-
startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PHOTO);
-
}
-
}
只需要改动
Uri fileUri = FileProvider7.getUriForFile(this, file);
即可。
安装apk
同样的修改setDataAndType为:
-
FileProvider7.setIntentDataAndType(this,
-
intent, "application/vnd.android.package-archive", file, true);