Unable to add attachment to email (Android, Kotlin) - android

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

Related

How to show image in android remote view using content URI?

I am having trouble trying to show an image in a remote view with a contentUri. I have outlined the steps I took below. I believe I have followed the procedure correctly but still get a "Can't load widget" message. What am I doing wrong? Is the image saved to the correct storage area? Is the contentUri constructed correctly? Please help.
Blockquote
Save the image into my file directory. I can see the image successfully saved in data/data/com.mydomain/files/myImage.jpg when I check using Android Studio's Device File Explorer.
val file = File(applicationContext.filesDir, "myImage.jpg")
try {
FileOutputStream(file).use { out ->
myBitmap?.compress(Bitmap.CompressFormat.JPEG, 90, out)
}
} catch (e: IOException) {
e.printStackTrace()
}
Create a FileProvider in manifest and provider_paths.xml in res.xml
<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>
<paths>
<files-path name="name" path="." />
</paths>
Create a content Uri using getUriForFile. This returns a content uri of: content://com.mydomain.provider/name/myImage.jpg
val file = File(getAppInstance().filesDir, "myImage.jpg")
val contentUri = FileProvider.getUriForFile(
getAppInstance(),
BuildConfig.APPLICATION_ID + ".provider",
file
)
I pass the content Uri into Image() composable.
Image(
modifier = GlanceModifier.size(28.dp),
provider = ImageProvider(contentUri),
contentDescription = "Image"
)
Result on run:

Two file providers in android app image fileprovider not working

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.

Gmail error after generating csv file and sharing intent using Fileprovider: "Unable to attach file"

I am creating an app which generates a csv file, and then sends it via email.
It does work if I choose Whatsapp, or Google Drive, but if I select Gmail, I get a toast "Unable to attach file".
In the Logcat, I get the following lines:
2020-05-16 16:03:43.518 30779-30779/? W/Gmail: Gmail:No collectionId found for event forward
2020-05-16 16:03:43.518 30779-30779/? W/Gmail: Gmail:No itemId found for event forward
So I suppose it is a problem with my path, but I cannot manage to figure out what is the issue.
See the code below:
String today = new SimpleDateFormat("yyyyMMdd_HHmm").format(Calendar.getInstance().getTime());
//saving the file into device
FileOutputStream out = openFileOutput("Data_"+today+".csv", Context.MODE_PRIVATE);
out.write(data.toString().getBytes());
out.close();
//exporting
Context context = getApplicationContext();
File filelocation = new File(getFilesDir(), "Data_"+today+".csv");
Uri path = FileProvider.getUriForFile(context, "com.aaaa.bbbb.fileprovider", filelocation);
Intent fileIntent = new Intent(Intent.ACTION_SEND);
fileIntent.setType("text/csv");
String to[] = {"aaa#bbb.com"};
fileIntent.putExtra(Intent.EXTRA_EMAIL,to);
fileIntent.putExtra(Intent.EXTRA_SUBJECT, "Data_"+today+".csv");
fileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
fileIntent.putExtra(Intent.EXTRA_STREAM, path);
Log.d(LOG_TAG,"filelocation = " + filelocation.toString());
Log.d(LOG_TAG,"Uri = " + path.toString());
startActivity(Intent.createChooser(fileIntent, "Send email"));
The file provider xml:
<paths>
<files-path
name="data"
path="."/>
</paths>
Here is the provider definition from the manifest:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.aaaa.bbbb.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_path" />
</provider>
The log.d provides the following:
2020-05-16 16:16:40.745 2030-2030/com.aaaa.bbbb D/Export: filelocation = /data/user/0/com.aaaa.bbbb/files/Data_20200516_1616.csv
2020-05-16 16:16:40.745 2030-2030/com.aaaa.bbbb D/Export: Uri = content://com.aaaa.bbbb.fileprovider/data/Data_20200516_1616.csv
Any idea of what is wrong?

Couldn't find meta-data for provider with authority

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"

Don't attach file and send by email

I define FileProvider in manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="root"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths"/>
</provider>
and write paths :
<files-path path="files/" name="files_name" />
I put file "1.txt" in "root"/files/1.txt
Created intent for send file by email:
val intentToSendToBd = Intent(Intent.ACTION_SEND)
val file = File(context.filesDir,"files/1.txt")
val ur = FileProvider.getUriForFile(context, "root", file )
intentToSendToBd.setType("text/plain")
intentToSendToBd.putExtra(Intent.EXTRA_STREAM, ur)
intentToSendToBd.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intentToSendToBd.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
And finally I get "couldn't attach file" in EmailApp.
I am using this code to share mp3 file using send_imtent
val sdCard = Environment.getExternalStorageDirectory()
val directory = File(sdCard.absolutePath + "/Demo Mobile/VoiceMail")
val f = File(directory, sharingFileName + ".mp3") //or any other format supported
**val uri = Uri.parse("file://" + f.absolutePath)**
val share = Intent(Intent.ACTION_SEND)
share.putExtra(Intent.EXTRA_STREAM, uri)
share.setType("audio/mp3")
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(Intent.createChooser(share, "Share Voicemail File"))
Thanks, Happy Coding...

Categories

Resources