2016-06-21 119 views
14

我跟着this Google tutorial开始意图捕获图像new Intent(MediaStore.ACTION_IMAGE_CAPTURE)。本教程建议使用公共目录getExternalStoragePublicDirectory,这对我的应用程序非常有用。但是他们的例子改为使用getExternalFilesDir。然后传递文件的URI到意图MediaStore.EXTRA_OUTPUThave to get a content URI,因为我想定位到Android N之前瞄准N我只是通过一个文件:// URI和每个人,但谷歌很高兴。现在在N我开始得到FileUriExposedException,似乎是not very favorableAndroid:如何获取内容:// URI在外部存储中的文件PUBLIC目录

所以因为我有一个这样的文件...

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元数据中指定哪条路径?所有options I can find用于私人目录。

+1

“那是正确的权力?” - 不,因为你不是'MediaStore'。 “如果我必须使用我自己的提供者共享公共文件,那么我可以在FILE_PROVIDER_PATHS元数据中指定什么路径?” - ''给你外部存储的根。 'FileProvider'没有办法指定你正在尝试使用的目录。 – CommonsWare

+0

@CommonsWare如果FileProvider无法使用该目录,那么我是唯一使用私有目录还是停止目标N的选项?这似乎很愚蠢。感谢您的建议。 – Paul

+0

“如果FileProvider无法使用该目录” - 这不是我写的。这就是说,由于你想要的子目录的细节因设备而异,试图使用''会有风险。 “那么我唯一的选择是使用私人目录还是停止定位N?” - 没有。你可以编写你自己的'ContentProvider'。或者,你可以为我的'StreamProvider'编写一个插件。或者,您可以在外部存储上使用自定义目录,您可以从外部存储根目录控制其路径(尽管这可能是“私人目录”的含义)。 – CommonsWare

回答

5

TL:DR <external-path name="MyAppFolder" path="." />有效,但安全吗?您需要自己制作FileProvider。值得一读的是documentation,但这里有一个简短的概要。

正如@CommonsWare提到的,你需要从你的例子与"com.example.fileprovider"取代MediaStore.AUTHORITY,这是你会在你的清单,像这样定义的权威......

<application>标签在AndroidManifest,类型以下内容:

<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>标签链接到一个XML文件中的所有您FileProvider被允许触摸路径。但这是我一直在自己挣扎的文件。

朝你联系,在Save the Full-size Photo节结束的教程结束时,谷歌的例子给出这种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提供给其他应用程序(如相机),然后可以读取和写入其解析的文件。

如果有任何危险或缺点,我很乐意听到他们。

3

这是我在我的应用程序中使用的图片公共目录。

  1. 创建这样的文件:

    File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME"); 
    
  2. 指定的文件提供的元数据如下路径:

    <paths> 
        <external-path name="secure_name" path="Pictures/YOUR_APP_NAME" /> 
    </paths> 
    

“secure_name”用于隐藏子目录的名称(“YOUR_APP_NAME”在这种情况下),你出于安全原因共享。

“图片”对应于Environment.DIRECTORY_PICTURES

  • 获取UriIntent派:

    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); 
    
  • 相关问题