I'm trying to send file to another app for using Intent. I used targetSdkVersion 25 in my gradle. My app works fine on android version < 24. When android version >= 24, i'm using FileProvider for sending file to another app and it's not working here.
This is step I using for FileProvider:
manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="sp.xxx.yyy.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
file_paths:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="Android/data/sp.xxx.yyy/" name="app_root" />
<external-path path="Android/data/sp.xxx.yyy/files/" name="files_root" />
<external-path path="." name="external_storage_root" />
</paths>
Open intent:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
File file = new File(path);
Log.e("Utils" , "file exists: " + file.exists());
Uri contentUri = FileProvider.getUriForFile(context, "sp.xxx.yyy.fileProvider", file);
intent.setData(contentUri);
} else {
Uri contentUri = Uri.parse(path);
intent.setData(contentUri);
}
context.startActivity(intent);
When use FileProvider for sending file uri to another app, I see that other app receive data like this:
Intent { act=android.intent.action.VIEW dat=content://sp.xxx.yyy.fileProvider/external_storage_root/Android/data/sp.xxx.yyy/files/filetosending.txt flg=0x10400002 cmp=sp.zzz/sp.zzz.MainActivity launchParam=MultiScreenLaunchParams { mDisplayId=0 mFlags=0 } }
Another app not works with data received content://sp.xxx.yyy.fileProvider/external_storage_root/Android/data/sp.xxx.yyy/files/filetosending.txt
What's wrong in my code? Have any suggestion for resolve this problem? Thank your support.
Related
I found out that I am unable to attach a file to a mail client that I'm opening from my app on Android 11.
It might be related to the storage access changes in Android 11, but I'm not sure how I need to adjust the code for it to be supported.
I store privately a log file with in external cache dir.
My intent is :
val intent = Intent(Intent.ACTION_SENDTO)
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("abc#gmail.com"))
intent.putExtra(Intent.EXTRA_STREAM, logFile)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = type
intent.data = Uri.parse("mailto:")
if (intent.resolveActivity(packageManager) != null) {
startActivity(Intent.createChooser(intent, "Send email via::"))
return true
}
and the file is :
val logFile = File(ctx.externalCacheDir, "MyLogFile.log")
Solution with FileProvider which didn't work :
I changed this line :
intent.putExtra(Intent.EXTRA_STREAM, logFile)
into this :
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(activity, "${BuildConfig.APPLICATION_ID}.fileprovider", logFile))
and manifest :
<provider
android:name="androidx.core.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>
and provider_paths :
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path name="MyLogFile" path="."/>
</paths>
I solved with replacing:
val intent = Intent(Intent.ACTION_SENDTO)
with
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("mime/type");
and in manifest:
<queries>
<intent>
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="*/*" />
</intent>
</queries>
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
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))
Hi I'm currently experiencing error on starting an intent due to FileProvider causing NPE. I followed the steps provided here but I still got the error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
I am not sure as well if the provider_paths.xml is being used here. Here's my code so far:
Manifest:
<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>
res/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:
Uri uri=FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID+".provider", file);
the itself seems to be the cause of error here.
BuildConfig.APPLICATION_ID should return your packagename, however, in my case it returned "android.support.v4". I consider using getPackagename() and it will work just fine!
So just change
FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider", file);
to:
FileProvider.getUriForFile(this,
getPackagename() + ".provider", file);
Refer to this link for your answer.
enter link description here
First, this:
android:authorities="${applicationId}.fileprovider"
you are using this:
FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider", file);
chabge this :
FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".fileprovider", file);
Since I don't know which of those is what you really want, I cannot suggest a fix.
I am using this :
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>
XML file :
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="media_folder" path="." />
</paths>
In Java :
FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider", file);
Trying to open an image in the default gallery app. I can't resolve this issue following the steps:
My file path is /data/data/{applicationName}/cache/file.jpg
Intent:
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(filePath);
intent.setDataAndType(FileProvider.getUriForFile(this, getApplicationContext()
.getPackageName() + ".provider", file),"image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
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
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
</paths>
I've tried changing the path and name in provider_paths but no luck.
Replace:
<external-path
name="external_files"
path="." />
with:
<cache-path name="external_files" />
as your path seems to be in getCacheDir().