Android中getUriForFile访问外部存储/DCIM失败问题求助
Hey there, let's break down exactly why you're hitting this error and how to fix it step by step.
Why the Error Happens
First, let's clarify what those FileProvider paths actually map to:
- The
external-files-pathyou're using points to your app's own dedicated external storage directory (/storage/emulated/0/Android/data/com.perinote.perinote/files/), which is only for files your app creates and manages. This directory is private to your app (though technically accessible by other apps with storage permissions, it's not part of the public external storage like DCIM). - When you try to share a file from
/DCIM/, you're trying to access a public external storage location that's not included in the root directories your FileProvider is configured to handle. Hence theIllegalArgumentException—FileProvider can't find a configured root that includes the DCIM path.
As for why cache files work? That's because cache directories (either internal getCacheDir() or external getExternalCacheDir()) fall under the cache-path or external-cache-path entries in your FileProvider config. Those paths are explicitly mapped to your app's own storage, so FileProvider can resolve them without issues.
How to Fix It
To share files from the public DCIM directory, you need to update your FileProvider configuration to include access to public external storage, and adjust your Uri generation code accordingly.
1. Update Your FileProvider Path Configuration
Open your res/xml/file_paths.xml (or whatever file you're using for FileProvider paths) and add an entry for public external storage. You can either open the entire public storage, or restrict it just to the DCIM directory for better security:
<!-- Option 1: Allow access to the entire public external storage root --> <external-path name="public_external" path="." /> <!-- Option 2: Restrict access only to the DCIM directory (recommended) --> <external-path name="public_dcim" path="DCIM/" />
external-pathmaps directly toEnvironment.getExternalStorageDirectory()(which is/storage/emulated/0/on most devices).- The
nameattribute is a placeholder used in the generated Uri (it doesn't affect the actual file path). - The
pathattribute narrows down the accessible directory—using"DCIM/"means FileProvider will only allow access to files under/DCIM/.
2. Generate the Correct Uri for DCIM Files
When creating the Uri for your DCIM file, use the file path that points to /DCIM/ and let FileProvider resolve it using your new configuration. For example:
// Get the DCIM directory File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); File targetFile = new File(dcimDir, "your_target_file.jpg"); // Generate the content Uri using your FileProvider authority Uri contentUri = FileProvider.getUriForFile( getApplicationContext(), "com.perinote.perinote.fileprovider", // Your FileProvider authority targetFile );
3. Handle Permissions (Critical for Android 6.0+)
Make sure you have the necessary permissions to read from public external storage:
- Add this permission to your
AndroidManifest.xml:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - For Android 6.0 (API level 23) and above, you also need to request this permission at runtime before accessing the DCIM file.
4. Adapt to Scoped Storage (Android 10+)
If you're targeting Android 10 (API level 29) or higher, scoped storage changes how apps access public files:
- For Android 10, you can temporarily use
android:requestLegacyExternalStorage="true"in your<application>tag to use the old storage model, but this is a temporary workaround. - For Android 11+, it's better to use the
MediaStoreAPI to access DCIM files instead of directly accessing the file path. This is the long-term, compliant approach for scoped storage.
内容的提问来源于stack exchange,提问作者Peri Hartman

