I have an Image File stored in sd card with an Absolute path as - storage/4469-0C17/DCIM/... and another image stored in internal storage with an absolute path - /storage/emulated/0/
I am using FileProvider to share it with external apps.
Now, I am able to share images stored in internal-storage but for the image stored in external storage, it throws an error as -
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/4469-0C17/DCIM/....
My Manifest -
<manifest>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
.....
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>
</manifest>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Code -
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
File imageFileToShare = new File(filePath);
Uri imageURI = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", imageFileToShare);
share.putExtra(Intent.EXTRA_STREAM, imageURI);
share.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(share, "Share Image"));
and another image stored in internal storage with an absolute path
That is what the Android SDK refers to as external storage.
but for the image stored in external storage, it throws an error as -
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/4469-0C17/DCIM/....
First, that is removable storage, not external storage.
Second, FileProvider does not support removable storage.
Instead of using FileProvider which as you have seen yourself is very limited you better derive your own provider from ContentProvider.
Then you can serve any file you want.
CommonsWare has a nice example how to set up such a file provider.
Add to your provider_paths.xml this:
<root-path path="." name="external_files" />
Related
I want to allow the user the ability to download a file to the shared android "Download" directory (preferably) on either the internal storage or the SD card (if it exists). I can download a file to the internal storage but can't seem to get it to work on the SD card and everything I've looked at on here is either deprecated, incomplete, or doesn't work.
Here's my download code:
if(downloadToSdCard) {
File path = new File(browser.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), filename);
Uri downloadsUri = FileProvider.getUriForFile(browser, "my.app.fileprovider", path);
request.setDestinationUri(downloadsUri);
} else {
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
}
downloadManager.enqueue(request);
Related bits in my manifest:
<application
android:requestLegacyExternalStorage="true"
...>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="my.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
And filepaths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Used when sharing images from the internet to create a temp image to download to -->
<cache-path name="shared_images" path="images/"/>
<cache-path name="text_to_speech_gen" path="text_to_speech_gen/"/>
<!-- Used when downloading files to allow external apps to open downloaded files -->
<external-path name="attachment_file" path="."/>
</paths>
I'm really struggling to get my head around how the android file system works so explanations with the answer would be appreciated. I've tried reading the official documentation but I just end up falling down endless rabbit holes of confusion. Thanks!
I am using FileProvider to install apk from my app. Followed many stackoverflow questions but still facing this issue
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.tssi.myapptour/files/download/myapp_newSigned.apk
My provider in manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.tssi.myapptour.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
my file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="download" path="download/" />
<!-- <external-path name="download" path="Android/data/com.tssi.myapptour/files/download/" />-->
</paths>
And my code for calling apk
String strApkToInstall = "myapp_newSigned.apk";
File fileApkToInstall = new File(getExternalFilesDir("download"), strApkToInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri fileUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider",
fileApkToInstall);
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Your file is in getExternalFilesDir(). That does not match files-path in your FileProvider metadata. Either:
Switch to getFilesDir() (a much better solution from a security standpoint), or
Switch to external-files-path
See the FileProvider documentation for more about the mapping between filesystem locations and metadata entries.
Currently, FileProvider getUriForFile method generates IllegalArgumentException when the file is on an external SD
When the file is in the device memory (under /storage/emulated/0), it works fine.
Uri videoUri = FileProvider.getUriForFile(this,
getApplicationContext().getPackageName() + ".provider",
new File(videoPath));
here videoPath had the following value :
videoPath = /storage/extSdCard/Android/data/com.podcastcutter.debug/files/episodeMp3/TEDTalks (video)/Why you should love statistics - Alan Smith.mp4
My Manifest file contains :
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
and here the provider_paths :
<external-path name="external_files" path="."/>
How can I modify the FileProvider configuration to solve this problem?
Thanks in advance.
Exception generated:
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/extSdCard/Android/data/com.podcastcutter.debug/files/episodeMp3/TEDTalks (video)/Why you should love statistics - Alan Smith.mp4
android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
Additional Configuration information:
compileSdkVersion 25
buildToolsVersion "23.0.3"
minSdkVersion 16
targetSdkVersion 25
support libraries version : 25.1.1
I added in my provider.xml this line and works fine to get file URI from SD card:
<root-path name="external_files" path="/storage/" />
Complete xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="/storage/" />
</paths>
How can I modify the FileProvider configuration to solve this problem?
You can't. FileProvider does not support removable storage.
Your provider path is the wrong type. Your videoPath shows a path to your app's external storage but your provider path is using external-path which links to the device root external storage. (/storage/emulated/0)
Change your provider path to be <external-files-path>...</external-files-path>
I am trying to use FileProvider to play a video from private path.Facing
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/XXXXX(Package)/files/Videos/final.mp4
Code:
<paths>
<files-path path="my_docs" name="Videos/" />
</paths>
Java code:
File imagePath = new File(getFilesDir(), "Videos");
File newFile = new File(imagePath, "final.mp4");
Log.d(TAG, "-------------newFile:"+newFile.exists());//True here
//Exception in below line
Uri contentUri = FileProvider.getUriForFile(this,"com.wow.fileprovider", newFile);
Manifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.wow.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
Any clues on this?
Thanks
Nitz
You have your name and your path flipped. name is what goes in the Uri, and path is the relative location within the root on the filesystem.
Go with:
<paths>
<files-path name="my_docs" path="Videos/" />
</paths>
change your provider XML to this.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
<root-path name="external_files" path="/storage/" />
</paths>
I had the very same basic situation. I defined everything correctly (files-path in xml) but there is one more thing which leads to the same exception. I add another answer just as an addition and a comment would not be well readable.
I created/read the directory where i store the files like:
context.getDir("Documents", Context.MODE_PRIVATE)
This leads to a path like:
/data/user/0/ch.myapp/app_Documents/6c3c70d5-af66-48ef-8dfc-f4341de4e1bd.docx
Then i changed creating the directory to:
File directory = new File(context.getFilesDir(), "Documents");
if (!directory.exists()) {
directory.mkdir();
}
This leads to a path like:
/data/user/0/ch.myapp/files/Documents/6c3c70d5-af66-48ef-8dfc-f4341de4e1bd.docx
According to the documentation Open a directory the two methods should be equivalent as far as i understand it. But it creates a different path... Maybe the formulation is just not clear for me in the documentation, but for me its wrongly written.
getDir(name, mode)
Creates a new directory (or opens an existing directory) within your
app's unique file system directory. This new directory appears inside
the directory provided by getFilesDir().
I have some files in custom folder in the internal storage. I need to open the files using external application like Adobe. I planned to open using FileProvider. But the third party application is stopped when trying to open the the document. I really don't know what mistake I did in the code.
package name = "com.example.doc"
activities are in package = "com.example.doc.activities"
manifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.doc.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
android:readPermission="com.example.doc.fileprovider.READ">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepath" />
</provider>
res/xml/filepath.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files" path="." />
</paths>
activity
//tempfilePath = /data/data/com.example.doc/files/RBC/sample.docx
File file = new File(tempfilePath);
Uri exportUri = FileProvider.getUriForFile (this, "com.example.doc.fileprovider", file);
Intent docViewIntent = new Intent();
docViewIntent.setAction(Intent.ACTION_VIEW);
docViewIntent.setDataAndType(exportUri , extensionType);
docViewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
docViewIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(docViewIntent);
Do we need to specify any permission in manifest?
Any help would be appreciated..
Thanks
Jomia