## 兼容文件权限7.0 对于第一次遇到7.0文件权限问题已经有1年多两年的时间了,相信大家也都知道需要适配,才能让应用之间共享文件的使用。 ### 用法 我总结封装了一下,现在兼容文件权限只需要两步: * 第一步:在manifest文件中配置 首先申明文件的读写权限 ``` ``` 然后再在application标签中增加provider标签 ``` ``` 保持这个不变,核心有两个地方:**1、`android:authorities`属性**,一般都是自己应用的包名+fileprovider中间用"."连接;**2、`android:resource`属性**,本库中我为了方便把所有的都定义了出来(要求v21版本以上的除外),稍后解释。 * 第二步:在需要传递或使用文件共享的地方转换Uri: ``` PermissionHelper.getUri(/*context*/this, intent, file); ``` 这第二步,需要设置`authorities`属性和`FLAG_GRANT_READ_URI_PERMISSION` flag,我提供了以下几种方式: ``` public static Uri getUri(@NonNull Context context, @NonNull File file) { return getUri(context, file, context.getPackageName() + ".fileprovider"); } public static Uri getUri(@NonNull Context context, @NonNull File file, @NonNull String authority) { return getUri(context, null, file, authority); } public static Uri getUri(@NonNull Context context, @NonNull Intent intent, @NonNull File file) { return getUri(context, intent, file, context.getPackageName() + ".fileprovider"); } public static Uri getUri(@NonNull Context context, Intent intent, @NonNull File file, @NonNull String authority) { Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (intent != null) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } uri = FileProvider.getUriForFile(context, authority, file); } else { uri = Uri.fromFile(file); } return uri; } ``` 代码很简单,就是设置和不设置flag和默认和不默认属性的两两组合。前两个是不设置flag的,后两个默认和不默认`authorities`属性的。最后一个方法就是实现核心,也挺简单,在7.0以后才加这些配置,不然直接使用`Uri.fromFile(file)`返回即可。 使用例子:例如使用intent打开相机应用,并传递一个文件过去的时候,就可以这样使用: ``` private void openCamera(String dir) { File file = new File(dir, System.currentTimeMillis() + ".jpg"); final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, PermissionHelper.getUri(/*context*/this, intent, file)); startActivity(intent); } ``` 这里的dir目录需要在第一步中的xml中申明的目录中存在。 ### 目录结构 这里的目录有如下几个: * file_paths.xml 对应Context.getFilesDir()目录 * cache_paths.xml 对应Context.getCacheDir()目录 * external_paths.xml 对应Environment.getExternalStorageDirectory()目录 * external_files_paths.xml 对应Context.getExternalFilesDir(String)目录 * external_cache_paths.xml 对应Context.getExternalCacheDir()目录 我将这些目录路径打印出来就是如下的结果: ``` filePath = /data/user/0/${packageName}/files cachePath = /data/user/0/${packageName}/cache externalPath = /storage/emulated/0 externalFilePath = /storage/emulated/0/Android/data/${packageName}/files externalCachePath = /storage/emulated/0/Android/data/${packageName}/cache ``` ### 扩展 当然,具体业务中最好还是不要把这个目录的所有文件都共享,因为这可能不安全,我这样写只是一个默认的,能不出问题的方案而已。 想要深入了解如何共享这些目录文件的话,可以去看看这两篇文章 [Setting up file sharing](https://developer.android.google.cn/training/secure-file-sharing/setup-sharing) [FileProvider](https://developer.android.google.cn/reference/android/support/v4/content/FileProvider)