系统应用使用FileProvider的坑

高版本的对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用去实现,这篇博客来一起了解下它的实现原理 。
首先我们要明确一点,就是一个,所以需要在.xml里面对它进行声明:

和普通的不一样的是他多了一个..的meta-data指定了一个xml资源:
【系统应用使用FileProvider的坑】
文件URI
这个xml的作用在于为文件生成URI,root-path、files-path、cache-path这些标签代表父路径:
root-path : File("/")files-path : Context.getFilesDir()cache-path : context.getCacheDir()external-path : Environment.getExternalStorageDirectory()external-files-path : ContextCompat.getExternalFilesDirs(context, null)[0]external-cache-path :ContextCompat.getExternalCacheDirs(context)[0]external-media-path :context.getExternalMediaDirs()[0]
path属性代表子路径,name代表为"父路径/子路径"起的名字,

例如上面配置代表的就是我们为 new File(.(), "/") 这个路径起了个名字叫做files
val filesDir = File(context.getFilesDir(), "images/")val uri = FileProvider.getUriForFile(this, "me.linjw.demo.fileprovider.provider", File(filesDir, "test.jpg"))// uri就是把filesDir的路径转换"files",然后加上content://me.linjw.demo.fileprovider.provider// 即 "content://me.linjw.demo.fileprovider.provider/files/test.jpg"
从FileProvider的源码里面就能看到这部分的转换逻辑:
private static final String TAG_ROOT_PATH = "root-path";private static final String TAG_FILES_PATH = "files-path";private static final String TAG_CACHE_PATH = "cache-path";private static final String TAG_EXTERNAL = "external-path";private static final String TAG_EXTERNAL_FILES = "external-files-path";private static final String TAG_EXTERNAL_CACHE = "external-cache-path";private static final String TAG_EXTERNAL_MEDIA = "external-media-path";...int type;while ((type = in.next()) != END_DOCUMENT) {if (type == START_TAG) {final String tag = in.getName();final String name = in.getAttributeValue(null, ATTR_NAME);String path = in.getAttributeValue(null, ATTR_PATH);File target = null;if (TAG_ROOT_PATH.equals(tag)) {target = DEVICE_ROOT;} else if (TAG_FILES_PATH.equals(tag)) {target = context.getFilesDir();} else if (TAG_CACHE_PATH.equals(tag)) {target = context.getCacheDir();} else if (TAG_EXTERNAL.equals(tag)) {target = Environment.getExternalStorageDirectory();} else if (TAG_EXTERNAL_FILES.equals(tag)) {File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);if (externalFilesDirs.length > 0) {target = externalFilesDirs[0];}} else if (TAG_EXTERNAL_CACHE.equals(tag)) {File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(context);if (externalCacheDirs.length > 0) {target = externalCacheDirs[0];}} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP&& TAG_EXTERNAL_MEDIA.equals(tag)) {File[] externalMediaDirs = context.getExternalMediaDirs();if (externalMediaDirs.length > 0) {target = externalMediaDirs[0];}}if (target != null) {strat.addRoot(name, buildPath(target, path));}}}...private static File buildPath(File base, String... segments) {File cur = base;for (String segment : segments) {if (segment != null) {cur = new File(cur, segment);}}return cur;}