FileProvider - IllegalArgumentException:找不到已配置的根目录

FileProvider - IllegalArgumentException: Failed to find configured root

我正在尝试用相机拍照,但出现以下错误:

FATAL EXCEPTION: main
Process: com.example.marek.myapplication, PID: 6747
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example.marek.myapplication/files/Pictures/JPEG_20170228_175633_470124220.jpg
    at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
    at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
    at com.example.marek.myapplication.MainActivity.dispatchTakePictureIntent(MainActivity.java:56)
    at com.example.marek.myapplication.MainActivity.access0(MainActivity.java:22)
    at com.example.marek.myapplication.MainActivity.onClick(MainActivity.java:35)

AndroidManifest.xml:

<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.marek.myapplication.fileprovider"
        android:enabled="true"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
</provider>

Java:

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            Toast.makeText(getApplicationContext(), "Error while saving picture.", Toast.LENGTH_LONG).show();
        }
        // Continue only if the File was successfully created
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,
                    "com.example.marek.myapplication.fileprovider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="my_images" path="images/"/>
</paths>

我整天都在搜索这个错误并试图理解 FileProvider,但我不知道这个错误消息试图告诉我什么。如果你想要更多info/code,请在评论中写信给我。

您的文件存储在 getExternalFilesDir() 下。这映射到 <external-files-path>,而不是 <files-path>。此外,您的文件路径中不包含 images/,因此 XML 中的 path 属性无效。

res/xml/file_paths.xml 替换为:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path name="my_images" path="/" />
</paths>

2020 年 3 月 13 日更新

特定路径的提供程序路径如下:

  • <files-path/> --> Context.getFilesDir()
  • <cache-path/> --> Context.getCacheDir()
  • <external-path/> --> Environment.getExternalStorageDirectory()
  • <external-files-path/> --> Context.getExternalFilesDir(String)
  • <external-cache-path/> --> Context.getExternalCacheDir()
  • <external-media-path/> --> Context.getExternalMediaDirs()

参考:https://developer.android.com/reference/androidx/core/content/FileProvider

这也让我有点困惑。

问题出在您的 xml 文件中的 "path" 属性上。

来自这份文件FileProvider 'path' 是一个子目录, 但在另一份文件 (camera/photobasics) 中显示 'path' 是完整路径。

<?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>

我只是将此 'path' 更改为完整路径,它就可以正常工作。

检查您的设备提供的存储空间数量 - 不支持从辅助存储空间共享文件。查看 FileProvider.java 来源(来自 support-core-utils 25.3.1):

            } 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];
                }
            }

因此,他们只占用第一个存储空间。

另外可以看到getExternalCacheDirs()是通过ContextCompat接口获取存储列表的。请参阅 documentation 了解其限制(例如,它被告知不能识别 USB 闪存)。最好是自己从这个 API 生成一些存储列表的调试输出,这样你就可以检查存储路径是否与传递给 getUriForFile().

的路径匹配

已经有一个 ticket assigned (as for 06-2017) in Google's issue tracker, asking to support more than one storage. Eventually, I found SO question on this

我看到至少您没有提供与 file_paths.xml 中其他人相同的路径。 所以请确保您在 3 个地方提供完全相同的包名称或路径,包括:

  • android:authorities 清单中的属性
  • path file_paths.xml
  • 中的属性 调用 FileProvider.getUriForFile() 时的
  • authority 参数。

试试这个

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="my_images"
        path="" />
</paths>

如果您正在使用内部缓存,则使用。

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="cache" path="/" />
</paths>
  • Xamarin.Android 用户

这也可能是因为在针对 Android 7.1、8.0+ 时未更新您的支持包。将它们更新为 v25.4.0.2+ 并且此特定错误可能会消失(假设您已经按照其他人的说明正确配置了 file_path 文件)。


Giving context: I switched to targeting Oreo from Nougat in a Xamarin.Forms app and taking a picture with the Xam.Plugin.Media started failing with the above error message, so updating the packages did the trick for me ok.

我做了什么来解决这个问题 -

AndroidManifest.xml

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.mydomain.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"/>
        </provider>

filepaths.xml(允许 FileProvider 共享应用程序外部文件目录中的所有文件)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="files"
        path="/" />
</paths>

并在 java class -

Uri fileProvider = FileProvider.getUriForFile(getContext(),"com.mydomain.fileprovider",newFile);

启用 flavors (dev, stage) 后出现类似问题。

在添加风味之前,我的路径资源如下所示:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
    name="my_images"
    path="Android/data/pl.myapp/files/Pictures" />
</paths>

添加后android:authorities="${applicationId}.fileprovider" 在 Manifest 中 appId 是 pl.myapp.dev 或 pl.myapp.stage 取决于风格和应用程序开始崩溃。 我删除了完整路径并将其替换为点,一切都开始工作了。

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="my_images"
        path="." />
</paths>

Android官方文档说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>

But to make it work in the latest android there should be a "/" at the end of the path, like this:

<?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>

None 这对我有用。唯一可行的方法是不在 xml 中声明显式路径。所以这样做并开心:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="." />
</paths>

这里也有关于这个问题的优秀教程: https://www.youtube.com/watch?v=9ZxRTKvtfnY&t=613s

xml file_paths 文件中的以下更改对我有用。

 <external-files-path name="my_images" path="Pictures"/>
 <external-files-path name="my_movies" path="Movies"/>

我会迟到,但我找到了适合我的 it.Working 解决方案,我只是将路径 XML 文件更改为:

 <?xml version="1.0" encoding="utf-8"?>
<paths>
    <root-path name="root" path="." />
</paths>

我注意到有关 path.xml 文件的政策或行为在支持库 26 和 27 之间发生了变化。为了从相机捕获图片,我看到了以下变化:

  • 对于 26,我不得不使用 <external-path>path 参数中给出的完整路径。

  • 对于 27,我不得不使用 <external-files-path> 并且只使用 path 参数中的子文件夹。

所以支持库 27 对我特别有用,因为 path.xml 文件是

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path name="camera_image" path="Pictures/"/>
</paths>

这对我有用,因为 well.Instead 给出了完整路径我给了 path="Pictures" 并且工作正常。

<?xml version="1.0" encoding="utf-8"?>
 <paths>
  <external-files-path
    name="images"
    path="Pictures">
  </external-files-path>
 </paths>

I had the same problem, I tried the below code for its working.

1.Create Xml文件:provider_paths

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="my_images" path="myfile/"/>
</paths>

2。清单文件

 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.ril.learnet.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
 </provider>

3.In 你的 Java 文件。

      File file =  new File(getActivity().getFilesDir(), "myfile");
        if (!file.exists()) {
            file.mkdirs();
        }
        String  destPath = file.getPath() + File.separator + attachmentsListBean.getFileName();

               file mfile = new File(destPath);
                Uri path;
                Intent intent = new Intent(Intent.ACTION_VIEW);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                {
                    path = FileProvider.getUriForFile(AppController.getInstance().getApplicationContext(), AppController.getInstance().getApplicationContext().getPackageName() + ".provider", mfile );
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                } else {
                    path = Uri.fromFile(mfile);
                }
   intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setDataAndType(path, "image/*");
                    getActivity().startActivity(intent);

这取决于你想做什么样的存储,内部或外部

用于外部存储

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path name="my_images" path="my_images" />
</paths>

但对于内部存储,请注意路径,因为它使用 getFilesDir() 方法 这意味着您的文件将位于应用程序的根目录中 ("/")

  File storeDir = getFilesDir(); // path "/"

所以你的提供者文件必须是这样的:

<paths>
    <files-path name="my_images" path="/" />
</paths>

请注意,外部路径并未指向您的辅助存储,即 "removable storage"(尽管名称为 "external")。如果您得到 "Failed to find configured root",您可以将此行添加到您的 XML 文件。

<root-path name="root" path="." />

在此处查看更多详细信息FileProvider and secondary external storage

none 以上对我有用, 经过几个小时的调试,我发现问题出在 createImageFile(),特别是 absolute pathrelative path

我假设你们正在使用官方 Android 拍照指南。 https://developer.android.com/training/camera/photobasics

    private static File createImageFile(Context context) throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        mCurrentPhotoPath = image.getAbsolutePath();
        return image;
    }

记下 storageDir,这是创建文件的位置。所以为了得到这个文件的绝对路径,我干脆用image.getAbsolutePath(),这个路径在onActivityResult如果你需要拍照后的Bitmap图片

下面是file_path.xml,直接用.这样就用绝对路径了

<paths>
    <external-path
        name="my_images"
        path="." />
</paths>

如果拍照后需要位图

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Bitmap bmp = null;
        try {
            bmp = BitmapFactory.decodeFile(mCurrentPhotoPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

你好朋友试试这个

In this Code

1) 如何在清单中声明 2 个文件提供程序。

2) 文件下载的第一个提供商

3) 用于相机和图库的第二个提供程序

第 1 步

     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>

Provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="apks" path="." />
</paths>

第二供应商

     <provider
        android:name=".Utils.MyFileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true"
        tools:replace="android:authorities"
        tools:ignore="InnerclassSeparator">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_path" />
    </provider>

file_path.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="storage/emulated/0" path="."/>
</paths>

.Utils.MyFileProvider

Create Class MyFileProvider(仅创建 class 无任何方法声明)

当你使用 File Provider 时使用了 (.fileprovider) 这个名称,而你用于图像 (.provider) 时使用了这个名称。

如果有任何问题无法理解此代码,您可以联系 rp1741995@gmail.com 我会帮助您。

如果没有任何帮助并且您遇到错误

failed to find configured root that contains /data/data/...

然后尝试更改某些行,例如:

File directory = thisActivity.getDir("images", Context.MODE_PRIVATE);

至:

File directory = new File(thisActivity.getFilesDir(), "images");

并在 xml 文件中:

<files-path name="files" path="." />

这很奇怪,因为我访问的文件夹是 /images

这可能会解决每个人的问题: 添加了所有标签,因此您无需担心文件夹路径。 将 res/xml/file_paths.xml 替换为:

<?xml version="1.0" encoding="utf-8"?>
<paths>
  <external-path
    name="external"
    path="." />
  <external-files-path
    name="external_files"
    path="." />
  <cache-path
    name="cache"
    path="." />
  <external-cache-path
    name="external_cache"
    path="." />
<files-path
    name="files"
    path="." />
</paths>

编辑:2021 年 6 月 1 日

我们应该只使用我们需要的特定路径。 自己尝试备用路径并使用您需要的路径。

有关详细信息,请参阅已接受的答案

我的问题是我在不同类型的文件路径中有重叠的名称,如下所示:

<cache-path
    name="cached_files"
    path="." />
<external-cache-path
    name="cached_files"
    path="." />

在我将名称 ("cached_files") 更改为唯一后,我摆脱了错误。我的猜测是这些路径存储在一些 HashMap 或不允许重复的东西中。

我为此花了 5 个小时..

我已经尝试了以上所有方法,但这取决于您的应用程序当前使用的存储空间。

https://developer.android.com/reference/android/support/v4/content/FileProvider#GetUri

尝试代码之前先查看文档。

以我为例 因为 files-path 子目录将是 Context.getFilesDir()。 奇怪的是它 Context.getFilesDir() 注释了另一个子目录。

我要找的是

data/user/0/com.psh.mTest/app_imageDir/20181202101432629.png

Context.getFilesDir()

returns /data/user/0/com.psh.mTest/files

所以标签应该是

.....files-path name="app_imageDir" path="../app_imageDir/" ......

那就成功了!!

问题可能不仅仅是路径 xml。

以下是我的修复:

查看 android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile() 中的根课程:

    public File getFileForUri(Uri uri) {
        String path = uri.getEncodedPath();

        final int splitIndex = path.indexOf('/', 1);
        final String tag = Uri.decode(path.substring(1, splitIndex));
        path = Uri.decode(path.substring(splitIndex + 1));

        final File root = mRoots.get(tag); // mRoots is parsed from path xml
        if (root == null) {
            throw new IllegalArgumentException("Unable to find configured root for " + uri);
        }

        // ...
    }

这意味着 mRoots 应该包含请求的 uri 的标记。 所以我写了一些代码来打印mRoots和uri的标签,然后很容易发现标签不匹配

原来把provider权限设为${applicationID}.provider是个蠢主意!这个权限很常见,可能被其他提供者使用,这会弄乱路径配置!

我遇到了这个错误 Failed to find configured root that contains...

以下解决方法解决了我的问题

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="media" path="." />
</paths>

AndroidManifest.xml

<provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="[PACKAGE_NAME]"
      android:exported="false"
      android:grantUriPermissions="true">
         <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">
         </meta-data>
</provider>

ActivityClass.java

void shareImage() {
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this,"com.slappstudio.pencilsketchphotomaker", selectedFilePath));
        startActivity(Intent.createChooser(intent,getString(R.string.string_share_with)));
    }

您需要将 xml 文件从

更改为 file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="my_images" path="images/"/>
</paths>

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <exeternal-path name="my_images" path="Android/data/com.example.marek.myapplication/files/Pictures"/>
</paths>

我确定我迟到了,但下面对我有用。

<paths>
    <root-path name="root" path="." />
</paths>

花了 2 周时间寻找解决方案...如果您在尝试以上所有操作后到达这里:

1 - 验证您的标签提供商是否在标签应用程序内

<application>

    <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.companyname.Pocidadao.fileprovider" android:exported="false" android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data>
    </provider>

</application>

2 - 如果你尝试了很多路径都没有成功,那么用这个测试:

<?xml version="1.0" encoding="utf-8"?>
<paths>
  <cache-path name="cache" path="." />
  <external-path name="external" path="." />

  <root-path name="root" path="." />
  <files-path name="my_images" path="/" />
  <files-path name="my_images" path="myfile/"/>
  <files-path name="files" path="." />

  <external-path name="external_files" path="." />
  <external-path name="images" path="Pictures" />
  <external-path name="my_images" path="." />
  <external-path name="my_images" path="Android/data/com.companyname.yourproject/files/Pictures" />
  <external-path name="my_images" path="Android/data/com.companyname.yourproject/files/Pictures/" />

  <external-files-path name="images" path="Pictures"/>
  <external-files-path name="camera_image" path="Pictures/"/>
  <external-files-path name="external_files" path="." />
  <external-files-path name="my_images" path="my_images" />

  <external-cache-path name="external_cache" path="." />

</paths>

测试这个,如果相机工作,然后开始消除一些线条并继续测试...

3 - 不要忘记验证相机是否在您的模拟器中处于活动状态。

我的问题是错误的文件名: 我在 res/xml 下创建 file_paths.xml,而清单中的资源设置为 provider_paths.xml

<provider
        android:authorities="ir.aghigh.radio.fileprovider"
        android:name="android.support.v4.content.FileProvider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>

我将 provider_paths 更改为 file_paths,问题已解决。

您需要确保 file_paths.xml 文件的内容包含此字符串 => "/Android/data/com.example.marek.myapplication/files/Pictures/"

从报错信息来看,就是你的图片存放路径。查看预期示例

files_path.xml 下面:

<external-path name="qit_images" path="Android/data/com.example.marek.myapplication/files/Pictures/" />

如果您的文件路径类似于 /storage/emulated/0/"yourfile"

您只需要修改您的 FileProvider xml

<paths>
    <external-path name="external" path="." />
</paths>

然后需要分享文件的时候再调用这个函数

Intent sharingIntent = new Intent(Intent.ACTION_SEND);
                    Uri fileUri = FileProvider.getUriForFile(getContext(),
                            "com.example.myapp.fileprovider",
                            file);
                    sharingIntent.setType("*/*"); // any flie type
                    sharingIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
                    startActivity(Intent.createChooser(sharingIntent, "Share file"));

适用于 android M ~ Pie

@CommonsWare 的回答很棒。

但就我而言,我必须添加多个路径。

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="." />
    <files-path name="external_files" path="." />
</paths>