FileProvider 和辅助外部存储
Posted
技术标签:
【中文标题】FileProvider 和辅助外部存储【英文标题】:FileProvider and secondary external storage 【发布时间】:2017-03-12 02:46:39 【问题描述】:如何使用 FileProvider
从 SECONDARY 外部存储提供文件?
FileProvider
的当前实现只处理ContextCompat.getExternalFilesDirs
返回的第一个目录
...
else if (TAG_EXTERNAL_FILES.equals(tag))
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs.length > 0)
target = externalFilesDirs[0];
...
似乎没有办法为FileProvider
定义一个与辅助外部存储路径匹配的<path>
条目...
【问题讨论】:
二级外部存储是什么意思?ContextCompat.getExternalFilesDirs
返回的目录,数组索引 > 0。在大多数设备上,它可能是可移动 sd 卡。
AFAIK, FileProvider
不支持这个。您可以使用my StreamProvider
来安装一些东西,尽管不支持这种“开箱即用”。我已将其添加到StreamProvider
的待办事项列表中,因为您的观点很好。特别是由于这些位置不涉及应用程序权限,因此它们应该是可服务的,至少当它们存在时。正确处理可移动存储不可用但您要求提供它的情况可能会变得棘手。
【参考方案1】:
FileProvider 不支持二级存储,因为下面的代码:
来自 support:support-core-utils:26.1.0 FileProvider 的代码
else if (TAG_EXTERNAL_FILES.equals(tag))
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs.length > 0)
target = externalFilesDirs[0];// Code here, That's why!!!
else if (TAG_EXTERNAL_CACHE.equals(tag))
但是,FileProvider 中有一个特殊的 TAG:root-path,官方参考中没有提到。
if (TAG_ROOT_PATH.equals(tag))
target = DEVICE_ROOT;// DEVICE_ROOT = new File("/");
else if (TAG_FILES_PATH.equals(tag))
所以,root-path 匹配所有路径。
只需在您的 FileProvider xml 中键入此代码,然后 FileProvider 即可处理二级存储中的文件。
<root-path name="root" path="." />
请注意,它可能会泄露您的目录结构。
【讨论】:
【参考方案2】:为了处理位于外部 SD 卡上的文件,我将 provider_paths.xml 更改为
<paths>
<external-path path="." name="external_files" />
<root-path path="." name="sdcard1" />
</paths>
【讨论】:
【参考方案3】:所以我最终做了以下事情:
尝试通过FileProvider创建Uri,如果失败是因为:
java.lang.IllegalArgumentException: Failed to find configured root that contains
我只是在创建一个常规的 Uri。
这是我的代码:
try
uri = FileProvider.getUriForFile(context,
MY_AUTHORITY_STRING,
imageFile);
catch (Exception e)
CLog.d(TAG, e);
uri = Uri.fromFile(imageFile);
我不知道为什么,但它正在工作,FileProvider 无法访问文件(因为它在辅助外部存储中),然后在 catch 子句中成功创建了 uri。
奇怪的谷歌...非常奇怪。
【讨论】:
在 7.0+ 中崩溃【参考方案4】:作为解决方法,您可以使用绝对路径:
<!-- secondary external storage with path /storage/extSdCard -->
<root-path path="/storage/extSdCard/android/data/YOUR_PACKAGE/files/" name="extSdCard" />
<!-- secondary external storage with path /storage/sdcard1 -->
<root-path path="/storage/sdcard1/Android/data/YOUR_PACKAGE/files/" name="sdcard1" />
【讨论】:
对于较新的设备,外部路径取决于插入的 SD 卡,因为它使用参考 ID,因此无法使用绝对路径。【参考方案5】:答案是……FileProvider
不支持。在 Android 7 中,由于 file://
Uri 方案已弃用,这更是一个问题。
我发出了bug report。
【讨论】:
感谢错误报告和链接,另一个开发人员在那里提供了 FileProvider 的工作子类。以上是关于FileProvider 和辅助外部存储的主要内容,如果未能解决你的问题,请参考以下文章
使用 FileProvider uri 打开 PDF 文件会打开一个空白屏幕