使用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);


本文详细介绍了如何在Android应用中使用FileProvider处理7.0及以上版本的URI权限问题,包括在AndroidManifest.xml中的注册、file_paths.xml的配置,以及如何通过FileProvider7辅助类快速适配不同版本的intent.setData和setDataAndType方法,以实现拍照和APK安装的兼容性。
5105

被折叠的 条评论
为什么被折叠?



