For file in Cache dir , I can add this in xml to set FileProvider
<cache-path
name="image"
path="image/"/>
But if I storage file in External Cache Dir,I cannot get external-cache-path tag or something like that to set FileProvider.And
<external-path
name="image_external"
path="cache/image/"/>
did not help ,too.
This is my Manifest file:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.tizi.quanzi"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
This is the xml/file_paths file:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="image"
path="image/"/>
<external-path
name="image_external"
path="cache/image/"/>
</paths>
And this is my Code:
String RootPath = App.getApplication().getExternalCacheDir().getAbsolutePath();
String filePath = RootPath + "/image/" + fileName;
// done something there to save file
Intent shareIntent = new Intent();
Uri contentUri = FileProvider.getUriForFile(App.getApplication(),
App.getApplication().getPackageName(), new File(filePath));
App.getApplication().grantUriPermission(App.getApplication().getPackageName(),
contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
shareIntent.setData(contentUri);
shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.setType("image/*");
activity.startActivity(Intent.createChooser(shareIntent, "share image"));
And this is the error infomation:
/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tizi.quanzi, PID: 27487
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.tizi.quanzi/cache/image/o9xygODHtdP6HXqsuUZghVCsBKTtY4FJgO1MpnmX.jpg
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:678)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:377)
at com.tizi.quanzi.tool.ShareImage.shareImage(ShareImage.java:67)
at com.tizi.quanzi.tool.ShareImage.shareImage(ShareImage.java:61)
at com.tizi.quanzi.adapter.GalleryAdapter$2.onClick(GalleryAdapter.java:119)
at android.support.v7.app.AlertController$AlertParams$3.onItemClick(AlertController.java:956)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)
at android.widget.AbsListView.performItemClick(AbsListView.java:1145)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3042)
at android.widget.AbsListView$3.run(AbsListView.java:3879)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Update:
The way to go with the Support Library 24.2.0 and above is how #ashughes says in his answer.
On that version they added two new tags to the implementation of FileProvider.java to be able to reference the external files and cache directories.
private static final String TAG_EXTERNAL_FILES = "external-files-path";
private static final String TAG_EXTERNAL_CACHE = "external-cache-path";
If you want to dig more into it, you can take a look at the changes made on this commit.
Original answer:
I had the same problem. I took a look at the class FileProvider.java, and as you said, there is no tag for external cache dir, just the four below.
private static final String TAG_ROOT_PATH = "root-path";
private static final String TAG_FILES_PATH = "files-path";
private static final String TAG_CACHE_PATH = "cache-path";
private static final String TAG_EXTERNAL = "external-path";
What I do is to use the external-path tag. This tag will point to the root of the external directory not to the cache one. So you can either specify the rest of the path from there to the cache directory on path, or you can use a dot so it points to the root of the external directory.
<external-path
name="external_files"
path="."/>
When you were using
<external-path
name="image_external"
path="cache/image/"/>
The method getFileForUri was checking if the path of the file starts with /storage/emulated/0/cache/image/ which it doesn't, because the path of your file is /storage/emulated/0/Android/data/com.tizi.quanzi/cache/image/. And that's the reason you are getting the exception.
As of Support Library 24.2.0, you can use:
<external-cache-path name="name" path="path" />
See FileProvider docs for more details.
Following configuration works for me:
I use
<paths>
<external-cache-path name="external_files" path="."/>
<external-path name="external_files" path="."/>
</paths>
in my code.
and my provider looks like this
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.bqe.core.provider.CameraFilesProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/camera_files_provider_paths" />
my min sdk
minSdkVersion 21
Related
when the user choosing a file it's triggers this code...
public static void openFiles(File file, Context context) {
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
MimeTypeMap mimeType = MimeTypeMap.getSingleton();
String type = mimeType.getMimeTypeFromExtension(file.getName().substring(file.getName().lastIndexOf(".") + 1).toLowerCase());
//Toast.makeText(context, type, Toast.LENGTH_SHORT).show();
if (type == null) type = "*/*";
Intent share = new Intent(Intent.ACTION_VIEW);
share.setDataAndType(uri, type);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(share);
//context.startActivity(Intent.createChooser(share, file.getName()));
}
The Problem:
when i'm choosing a file from internal storage it's working fine, but when i try to open a file from external sd card i got this excaption
I/ViewRootImpl#f0cb2c4[MainActivity]: ViewPostIme pointer 0
I/ViewRootImpl#f0cb2c4[MainActivity]: ViewPostIme pointer 1
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.files, PID: 21495
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/5A85-D438/DCIM/Camera/20200406_100806.jpg
at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
at com.example.files.JFileAdapter.openFiles(MainActivity.java:596)
at com.example.files.JFileAdapter.clickItem(MainActivity.java:579)
at com.example.files.JFileAdapter.lambda$getView$0$JFileAdapter(MainActivity.java:501)
at com.example.files.-$$Lambda$JFileAdapter$7O8geCTLRGHMEPzMgOfCRCbnWso.onClick(Unknown Source:8)
at android.view.View.performClick(View.java:7862)
at android.view.View.performClickInternal(View.java:7831)
at android.view.View.access$3600(View.java:879)
at android.view.View$PerformClick.run(View.java:29359)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
I/Process: Sending signal. PID: 21495 SIG: 9
res/xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths >
<cache-path name="cache" path="." />
<files-path name="files" path="." />
<external-path name="files" path="." />
</paths>
Manifest
<provider
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="${applicationId}">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
what i'm doing wrong that he faild to open an external sd card file?
FileProvider normally does not serve from a removable micro sd card.
But for Android 10- it will do if you add a line to your xml file:
<root-path name="root" path="." />
You can even remove all other path declarations.
In my application there is a need where i have to EDIT an internal storage image and save the new to internal storage again. So i have tried to make an Intent.ACTION_EDIT in order to use the default Gallery app for editing the image.
if (it.fileName.fileType() == IMAGE_TYPE) {
createEditImageFile()
val intent = Intent(Intent.ACTION_EDIT).apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
putExtra(MediaStore.EXTRA_OUTPUT,
FileProvider.getUriForFile(this#MyActivity,BuildConfig.APPLICATION_ID,
File(currentEditPhotoPath)))
setDataAndType(uri, "image/*")
}
startActivity(intent)
return
}
So i get hte following exception which is reasonable since i dont have my FileProvider exported in the Manifest.
java.lang.SecurityException: Permission Denial: writing androidx.core.content.FileProvider uri content://{package_name}/external_path_files/Pictures/JPEG_20200720_163239_edit_5491322030710880687.jpg from pid=26681, uid=10206 requires the provider be exported, or grantUriPermission()
So when i change my in the Manifest.xml file to
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="true"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths" />
</provider>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
and the paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="files"
path="." />
<external-files-path
name="external_path_files"
path="." />
<external-path
name="external_files"
path="."/>
</paths>
CreateEditImageFile() if the following
#Throws(IOException::class)
private fun createEditImageFile(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile("JPEG_${timeStamp}_edit_", ".jpg", storageDir).apply {
currentEditPhotoPath = absolutePath
}
}
i have the following fail on the Build.
Manifest merger failed : Attribute provider#androidx.core.content.FileProvider#exported value=(false) from AndroidManifest.xml:158:13-37
is also present at AndroidManifest.xml:167:13-36 value=(true).
Suggestion: add 'tools:replace="android:exported"' to <provider> element at AndroidManifest.xml:155:9-163:20 to override.
I dont really understand the error, and the most weird is that the AndroidManifest.xml lines are not where the provider is defined.
How can i solve this? Thank you
I am trying to open log.txt via file provider on browser, however the app crashes with IllegalArgumentException,
below I have copied snippets I'm using. let me know if you require more details.
String mReportsONSD = Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator
+ "reports"
+ File.separator;
String Logfile = "logd.txt";
File newFile = new File(mReportsONSD+Logfile);
Intent intent = new Intent(Intent.ACTION_VIEW, null);
intent.setComponent(ComponentName.unflattenFromString("com.android.chrome/com.google.android.apps.chrome.Main"));
Uri logURI = FileProvider.getUriForFile(this, getPackageName(), newFile);
intent.setData(logURI );
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivity(intent);
paths.xml to access file from external storage.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files
name="external_files"
path="/" />
</paths>
Here is Logcat
Process: com.stylingandroid.fileprovider, PID: 12241
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/reports/logd.txt
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
at com.stylingandroid.fileprovider.MainActivity.startPlayer(MainActivity.java:136)
at com.stylingandroid.fileprovider.MainActivity$2.onClick(MainActivity.java:68)
at android.view.View.performClick(View.java:6261)
at android.widget.TextView.performClick(TextView.java:11157)
at android.view.View$PerformClick.run(View.java:23748)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
There is nothing named external-files in the FileProvider metadata spec. Change it to external-path:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="/" />
</paths>
Also:
You can replace new Intent(Intent.ACTION_VIEW, null); with new Intent(Intent.ACTION_VIEW);
Environment.getExternalStorageDirectory() is deprecated in Android Q and will be obsolete by next year, so I strongly recommend that you store your content somewhere else (e.g., the directory identified through getExternalFilesDir() on Context)
This is my code block:
notificationIntent.setDataAndType(FileProvider.getUriForFile(
context,
"TrySomething",new File(context.getFilesDir().getAbsolutePath() + "/update_file")
),ANDROID_PACKAGE);
And this is my XML file:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="myupdater" path="files/update_file"/>
</paths>
But i get this error:
java.lang.IllegalArgumentException: Failed to find configured root
that contains /data/data/com.example.trysomething/files/update_file
How can I fix it?
First Create Xml File inside src->xml folder Like
for example named file_paths_public.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="/storage/"/>
</paths>
then Add this Code in to your manifest file
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<your app package>.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths_public" />
</provider>
now create one function that will support both api 26 and below device
that returns some valid uri
public static Uri getUriFromFile(Context theCtx, File theSrcPath) {
Uri requirdUri;
// Above Compile SDKversion: 25 -- Uri.fromFile Not working
// So we have to use Provider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
requirdUri = FileProvider.getUriForFile(theCtx,
theCtx.getApplicationContext().getPackageName() + ".provider",
theSrcPath);
} else {
requirdUri = Uri.fromFile(theSrcPath);
}
return requirdUri;
}
now use this uri Whenever you want
like
File FilePath = Environment.getExternalStorageDirectory().toString()/update_file/<here your file name >
Uri shareImageUri = getUriFromFile(this, <your full file Path Add hear>)
Check if you have this in your manifest
<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>
provider_paths:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="directory_name" path="."/>
</paths>
Get file URI as
Uri fileUri = FileProvider.getUriForFile(context, getApplicationContext().getPackageName() + ".provider", fileName(FILE))
I'm getting this exception when trying to use FileProvider:
Java.Lang.IllegalArgumentException: Unable to find configured root for content://com.abc/Android/data/com.abc/files/345345345.pdf Java.Lang.IllegalArgumentException
I guess my file_paths.xml configures the FileProvider with the wrong path. My code:
file_paths.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="." name="." />
<files-path path="com.abc/Android/data/com.abc/files/" name="files" />
</paths>
androidManifest.xml
<application android:label="#string/AppName" android:icon="#drawable/ic_launcher">
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.abc" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths" />
</provider>
</application>
What values should I put in path and name in file_paths.xml, to expose the file with the content URI: content://com.abc/Android/data/com.abc/files/345345345.pdf?
my code which creates the URI:
File newFile = new File (Application.Context.FilesDir.AbsolutePath, filename);
Android.Net.Uri androidContentUri = FileProvider.GetUriForFile (Application.Context, Application.Context.PackageName, newFile);
System.Uri systemContentUri = SystemUri (androidContentUri);
return systemContentUri;
Your entry:
<files-path path="com.abc/Android/data/com.abc/files/" name="files" />
Should become:
<files-path path="files" name="files" />
Path in this case represents the files in the files/ subdirectory of your app's internal storage area.
This application private subdirectory is the same as the value returned:
Application.Context.FilesDir;
So the file location within your app is:
var path = Path.Combine(Application.Context.FilesDir.AbsolutePath, "files");