我已经按照 这个 Google 教程开始使用
new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
捕捉图像的意图。本教程建议使用带有 getExternalStoragePublicDirectory
的公共目录,这对我的应用程序非常有用。但他们的示例改为使用 getExternalFilesDir
。然后使用 MediaStore.EXTRA_OUTPUT
将文件的 URI 传递给意图,我必须获取内容 URI,因为我想定位 Android N。在定位 N 之前,我只需传递一个 file:// URI 以及除 Google 之外的所有人很高兴。现在,在 N 上,我开始得到 FileUriExposedException
,这似乎是 不太有利。
鉴于我有一个这样的文件...
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyAppFolder");
if (!storageDir.exists() && !storageDir.mkdir())
Log.w(TAG, "Couldn't create photo folder: " + storageDir.getAbsolutePath());
File image = new File(storageDir, timeStamp + ".jpg");
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
...我可以使用公共图片目录的内置提供程序来获取内容 URI 吗?如果是这样怎么办?
我尝试过类似的事情
takePictureIntent.putExtra(
MediaStore.EXTRA_OUTPUT,
FileProvider.getUriForFile(this, MediaStore.AUTHORITY, createImageFile()));
但它只是抛出
IllegalArgumentException:缺少 android.support.FILE_PROVIDER_PATHS 元数据
这个权威正确吗?如果我必须使用自己的提供程序来共享公共文件,那么我可以在 FILE_PROVIDER_PATHS 元数据中指定什么路径?我能找到的所有选项都是针对私有目录的。
TL:DR
<external-path name="MyAppFolder" path="." />
有效,但安全吗?
您需要自己制作
FileProvider
。值得阅读其文档,但这里有一个简短的概述。
正如@CommonsWare提到的,您需要将示例中的
MediaStore.AUTHORITY
替换为"com.example.fileprovider"
,这是您将在清单中定义的权限,如下所示...
在 AndroidManifest 的
<application>
标记中,键入以下内容:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
您遇到的异常是由于没有
<meta-data>
标签链接到包含您的 FileProvider
允许触及的所有路径的 xml 文件。但正是这个文件中的内容让我一直在与自己斗争。
在您链接的教程的末尾,在保存全尺寸照片部分的末尾,Google为此提供的示例
file_paths.xml
是:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
在您的示例中,"my_images"
将替换为 "MyAppFolder"
。在该教程中,Google 声称
路径组件对应于使用Environment.DIRECTORY_PICTURES调用时getExternalFilesDir()返回的路径。确保将 com.example.package.name 替换为应用程序的实际包名称。
...输入该内容让我意识到这并不是指您和我正在寻找的公共图片目录。这解释了为什么使用该路径会产生此异常:
java.lang.IllegalArgumentException:无法找到包含 /storage/emulated/0/Pictures/MyAppFolder/{filename}.jpg 的已配置根目录
我将把它留在这里以供将来参考,然后继续回答您的大问题 - 您可以指定什么路径来允许其他应用程序与您的针对 API 级别 24+ 的应用程序创建的公共图片目录中的文件进行交互?
正如@CommonsWare所说,“所需子目录的详细信息因设备而异”,因此您无法声明公共图片目录的路径,但我确实找到了一种可行的方法。
<external-path name="MyAppFolder" path="." />
将允许您的 FileProvider
向其他应用程序(如相机)提供内容 URI,然后其他应用程序可以读取和写入其解析的文件。
如果这有任何危险或缺点,我很想听听。
这是我在我的应用程序中使用的图片公共目录。
像这样创建文件:
File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME");
在文件提供者的元数据中指定以下路径:
<paths>
<external-path name="secure_name" path="Pictures/YOUR_APP_NAME" />
</paths>
“secure_name” 用于隐藏您出于安全原因共享的子目录的名称(“YOUR_APP_NAME”)。
“图片”对应
Environment.DIRECTORY_PICTURES
。
获取
Uri
并使用Intent
发送:
final Uri theUri = FileProvider.getUriForFile(activity,
getString(R.string.fileprovider_authorities),
theFile);
theIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
theIntent.putExtra(MediaStore.EXTRA_OUTPUT, theUri);
对于系统下载文件夹中的子目录:(paths.xml)
<paths>
<external-path name="files_downloader" path="Download/MyFilesDownloader"/>
</paths>