I have an export button in my app that executes the below code. The email app opens correctly with the subject etc., but it's missing the attachment. I don't seem to be able to get the attachment to work. Any ideas what I'm doing wrong?
val filename = "Export.csv"
val path = context?.getExternalFilesDir(null) //get file directory for this package
//create fileOut object
val fileOut = File(path, filename)
//delete any file object with path and filename that already exists
fileOut.delete()
//create a new file
fileOut.createNewFile()
//append the header and a newline
fileOut.appendText("Case Number,Form Type,Status,Last Updated Date")
fileOut.appendText("\n")
for (item in arrayAll) {
fileOut.appendText("${item.number},${item.formType},${item.status},${item.LUD}")
fileOut.appendText("\n")
}
val contentUri = FileProvider.getUriForFile(this.requireContext(),"${BuildConfig.APPLICATION_ID}.fileProvider", fileOut)
val emailIntent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // only email apps should handle this
putExtra(Intent.EXTRA_SUBJECT, "Export.csv")
putExtra(Intent.EXTRA_STREAM, contentUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
this.startActivity(emailIntent)
Manifest:
<provider
android:authorities="${applicationId}.fileProvider"
android:name="androidx.core.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:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<root-path name="root" path="." />
</paths>
Following from you latest comment; According to the Android docs Intent.ACTION_SENDTO is for when you don't want attachments, I think you need to change this line val emailIntent = Intent(Intent.ACTION_SENDTO).apply { to
val emailIntent = Intent(Intent.ACTION_SEND).apply { to get your email app to display the attachment
I am sharing the app with the file provider and I want to share the image from the bitmap.
I have two file providers number one is for share apk, number two for share image. apk file provider works good but the image share file provider not sharing images. if I share an image to WhatsApp, Gmail it says file format does not support it.
fileprovider.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path
name="apk"
path="/"/>
</paths>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path name="img" path="my_images/"/>
</paths>
imagesharefrombitmap.kt
imgBtnShare.setOnClickListener {
shareImage()
loadingDialoglordshiva.startDialog()
}
}
private fun shareImage() {
val bitmapShare = getBitmapFromView(relLayout)
val filename = "${System.currentTimeMillis()}.jpg"
val cachePath = File(externalCacheDir.toString() + "/my_images")
cachePath.mkdirs()
//create a png file
//create png file
val file = File(cachePath, filename)
val fileOutputStream: FileOutputStream
try {
fileOutputStream = FileOutputStream(file)
bitmapShare.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
fileOutputStream.flush()
fileOutputStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
val myImageFileUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider_paths",file)
//create a intent
//create a intent
val intent = Intent(Intent.ACTION_SEND)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(Intent.EXTRA_STREAM, myImageFileUri)
intent.type = "image/jpg"
startActivity(Intent.createChooser(intent, "Share with"))
loadingDialoglordshiva.dismissDialog()
}
Manifest_file_only_provider_showed
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lordshiva.myapplication.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/fileprovider"
/>
</provider>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lordshiva.myapplication.provider_paths"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
if i run this share intent is opening. but share to WhatsApp,Gmail or something its says file format is not supported . help me I don't know how to solve this.
I am solved by share bitmap image directly to intent.
I am trying to capture Image using camera Intent and send it to server.
I have followed the official doc https://developer.android.com/training/camera/photobasics
But getting exception while using FileProvider to get the Uri from the filepath.
I am getting an exception
Failed to find configured root that contains /storage/emulated/0/Android/data/com.example.app/files/Pictures/JPEG_20200310_160944_8900302509758571991.jpg
Code:
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Android/data/com.example.app/files" />
</paths>
AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
CameraActivity.kt
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
takePictureIntent.resolveActivity(packageManager)?.also {
val photoFile: File? = try {
viewModel.createFile()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
photoFile?.also {
photoURI= FileProvider.getUriForFile(
this,
"com.example.app.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
}
}
Please help me figure out where I am wrong.
Although I have checked the possible answers on stackoverflow but unable to resolve it.
Replace:
path="Android/data/com.example.app/files"
with:
path="."
<external-files-path> already points to the location that you are identifying in path.
I have integrated Snapchat's Creative Kit in my Android app. After processing, I receive an image from the server in the form of Byte Array which I am saving to the disk and then sending the file to the Snapchat's Creative Kit as shown below.
private fun downloadImage(
fileName: String,
imageByteArray: ByteArray?): Uri? {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state) {
val downloadDir = File(
Environment.getExternalStorageDirectory(), context?.getString(R.string.app_name)
)
if (!downloadDir.isDirectory) {
downloadDir.mkdirs()
}
val file = File(downloadDir, fileName)
var ostream: FileOutputStream? = null
try {
ostream = FileOutputStream(file)
ostream.write(imageByteArray)
ostream.flush()
ostream.close()
}
} catch (e: IOException) {
e.printStackTrace()
}
val snapCreativeKitApi = SnapCreative.getApi(context!!)
val snapMediaFactory = SnapCreative.getMediaFactory(context!!)
lateinit var snapPhotoFile: SnapPhotoFile
try {
snapPhotoFile = snapMediaFactory.getSnapPhotoFromFile(file)
} catch (e: SnapMediaSizeException) {
return
}
val snapPhotoContent = SnapPhotoContent(snapPhotoFile)
snapCreativeKitApi.send(snapPhotoContent)
}
}
I have also added provider in the manifest file as shown below:
<provider
android:name="androidx.core.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_app" />
</provider>
And in the provider_paths_app.xml, I have tried all the possible paths by referring this answer and none of them works.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="My App Name"
path="." />
</paths>
With the above path, I am getting the below error.
Couldn't find meta-data for provider with authority my.package.name.fileprovider
All I have to do is send this image to Snapchat but I am unable to figure out what I am doing wrong. Any help will be appreciated.
First, write the following tag in manifest under the <application> tag
<provider
android:name="androidx.core.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>
Then create a xml folder in res and create a file named: provider_paths.xml
and then copy paste the code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>
And now here's where most developers make mistakes: in your script, create your File with:
FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".provider", file);
<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/file_paths"></meta-data>
</provider>
This is my provider declaration, the value of ${applicationId} is "com.limxtop.research", make sure that the name of authorities is the same with that of the codes below.
// Create the file where the photo should save.
File file = null;
try {
file = createImageFile();
} catch (IOException e) {
break;
}
// The second parameter is the name of authorities.
Uri uri = FileProvider.getUriForFile(this,
"com.limxtop.research.fileprovider", file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, fullSizeRequestCode);
So, maybe your codes post here is not complete, there you should pass "my.package.name.fileprovider" as parameter some where.
In my case.
I have a library project .Let's call it :LibApk
When I code this : applicationId "my.package.name" in the build.grale(app)
when build gradle tell me that : Library projects cannot set applicationId.
applicationId is set to 'com.darcy.apkupdate' in default config.
So ,I delete applicationId "my.package.name" .
Then ,build.gradle look like this :
But I forgot update the AndroidManifest.xml file which use ${applicationId}
This is the problem!!!
So I changed the variable to constant .The result looks like below picture:
After This ,It's wokr for me!
Hope this is help you...
The problem here is, you use the class name .provider for authorities in manifest
and use .fileprovider class name in java code.
<provider
android:name="androidx.core.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_app" />
</provider>
Couldn't find meta-data for provider with authority my.package.name.fileprovider
Just rename fileprovider to provider
If the build's suffix is different, it makes sense to make a change like this.
FileProvider.getUriForFile(mContext.get(), BuildConfig.APPLICATION_ID + ".fileprovider", file)
In My Case;
Manifest File:
<provider
android:name="androidx.core.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>
Code:
import androidx.multidex.BuildConfig // NOT DO THIS!!!
val uri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID+ ".provider", _tempFile)
Exception:
java.lang.IllegalArgumentException: Couldn't find meta-data for provider with authority androidx.multidex.provider
Do not use androidx.multidex.BuildConfig, Because this values are not the values of our application:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package androidx.multidex;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "androidx.multidex";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "";
public static final int VERSION_CODE = -1;
public static final String VERSION_NAME = "";
public BuildConfig() {
}
}
{applicationId} == com.companyName.application
append ".provider"
which will be == com.example.test.provider
in xml authorities:com.example.test.provider
in activity Uri mPath = FileProvider.getUriForFile(this, "com.example.example.provider", imageFile);
FileProvider.getUriForFile(this, "{yourPAckageName}.fileprovider",
file);
to
FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".provider", file);
I spent a day finding a solution. This part is very important. That saved my day.
mImageFromCamera = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", mImageFile);
android:authorities="${applicationId}.fileprovider"
authorities must be same in xml and in code
First you use
File(getExternalFilesDir(null),context?.getString(R.string.app_name));
instead of
Environment.getExternalStorageDirectory(), context?.getString(R.string.app_name) // this is deprecated in API29
then use this
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
For more help: File Provider Description
You can replace your BuildConfig import class file name:
import androidx.multidex.BuildConfig;
with:
import com.yourAppName.BuildConfig;
This is Because of this authority name difference
<provider
android:name="androidx.core.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>
here Look
<pre>android:authorities="${applicationId}.provider" </pre>
Here the authority name is you packagename.provider
(com.example.app.provider)
val uri: Uri? = FileProvider.getUriForFile(
this.contexts,
BuildConfig.APPLICATION_ID + ".provider",
file
)
whenever we copy paste the code the authority may be change from one source to another. in stackoverflow some devs put in manifest ${applicationId}.provider" and in uri they put (.fileprovider) FileProvider.getUriForFile(
this.contexts,
BuildConfig.APPLICATION_ID + ".fileprovider",
file
) this is the problem now authority is different that is showing in log
what solved my problem is :
replace your paths app file by this :
take a look at files root, i determined the path with my app package name, change the pkg name to yours.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="files_root"
path="Android/data/com.my.newproject4" />
<external-path
name="external_files"
path="." />
</paths>
and also in your provider
use your package name instead of ${applicationId}
same as me here
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.my.newproject4.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
this is what worked with me
the only solution and way after long time of trying and searching
just this was the problem
maybe it helps someone
i hope for you a good luck
Change the authorities to a unique name to solve the issue like
android:authorities="${applicationId}.myUniquefileprovider"
also in java code
I just removed the '$' from android:authorities="${applicationId}.provider" and it works like a charm now.
Its fileprovider and not provider
android:authorities="${applicationId}.fileprovider"
I am creating a PDF file and saving it in local storage. When trying to open it, it is working perfect in all devices except in Android N. I am able to open PDF file in Android N using FileProvider, but it is displaying as blank.
This is my URI
content://com.products.provider/external_storage_root/Android/data/com.products/in_17052017_170502_1_1001.pdf
This is my code
Uri path;
File pdfFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
+ "Android" + "/" + "data" + "/" + "com.products" + "/" + file);
if (Build.VERSION.SDK_INT >= 24) {
path = FileProvider.getUriForFile(getActivity(), "com.products.provider", pdfFile);
} else {
path = Uri.fromFile(pdfFile);
}
// Setting the intent for pdf reader
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
try {
startActivity(pdfIntent);
} catch (ActivityNotFoundException e) {
Toast.makeText(getActivity(), "Can't read pdf file", Toast.LENGTH_SHORT).show();
}
The problem is with how you are setting the flags on the intent
pdfIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Instead, try this:
pdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
pdfIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Grzegorz Matyszczak's solution worked for my case. I had a very similar setup to Sabya Sachi. More specifically this line allowed me to see the PDF file (URI from FileProvider.getURIForFile call):
pdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
More info on grantUriPermissions here, under android:grantUriPermissions section.
As I can see that you have used FileProvider for Nougat.
You have to add a FileProvider tag in AndroidManifest.xml.
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
</provider>
A FileProvider can only generate a content URI for files in directories that you specify beforehand.To link this file to the FileProvider, add a element as a child of the element that defines the FileProvider.
<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/file_paths"/>
</provider>
You must specify a child element of for each directory that contains files for which you want content URIs. You can add them to a new file called res/xml/file_paths.xml. For example ,these XML elements specify two directories:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
<files-path name="my_docs" path="docs/"/>
</paths>
->you have to set your PDF directory path in file_paths.xml
For more detail refer this
Replace FileProvider class with MyFileProvider class:
path = MyFileProvider.getUriForFile(getActivity(), "com.products.provider", pdfFile);
where MyFileProvider should be a generic class which extends FileProvider:
public class MyFileProvider extends FileProvider {
}
Modify AndroidManifest by setting your MyFileProvider class location to android:name attribute in your provider section:
android:name=".utils.MyFileProvider"