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...
Related
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' m trying to create a temporary file and share it.
So I created this class:
public class GenerateFile {
public static File writeToFile(Context mcoContext, String sBody) {
String fileName = "LOG FILE_" + String.valueOf(System.currentTimeMillis()) +".txt";
File file = new File(mcoContext.getCacheDir(), fileName);
try{
FileWriter writer = new FileWriter(file);
writer.append(sBody);
writer.flush();
writer.close();
return file;
}catch (Exception e){
Toast.makeText(mcoContext, "File write failed: " + e.toString(), Toast.LENGTH_LONG).show();
}
return null;
}
}
to generate a file that after I will share here:
String logContent = "123";
File filePath = new File(file.getAbsolutePath(), "external_files");
filePath.mkdir();
Uri uri = FileProvider.getUriForFile(StatusActivity.this, getPackageName(), filePath);
Intent intent = ShareCompat.IntentBuilder.from(StatusActivity.this)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.setAction(Intent.ACTION_VIEW) //Change if needed
.setDataAndType(uri, "text/*")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
And in the manifest there are already this permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/>
<uses-permission android:name="com.sec.android.provider.badge.permission.READ"/>
and the provider declaration
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="android.getqardio.com.gmslocationtest"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
The provider_paths class is defined in this way:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="share"
path="external_files"/>
</paths>
But it generate the message, when I try to share it by mail or telegram "Unable to attach file" or "Unsupported attachment". Also it seems to me that the file is not created.
Other apps do not have access to your app's getCacheDir(). FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION are for content Uri values, not file Uri values. And, on Android 7.0+ devices, your code should crash with a FileUriExposedException.
Use FileProvider to make your content available to other apps, and use FileProvider.getUriForFile() to get the Uri to put in the Intent.
So I follow the suggestion of #CommonsWare, and I edited my code. This is the final result:
public class GenerateFile {
public static Uri getFileURI(Context context, String nameFile, String content, String fileExtension) {
DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd");
Date date = new Date();
String fileName = dateFormat.format(date)+nameFile+fileExtension;
File file = new File(context.getCacheDir(), fileName);
try{
FileWriter writer = new FileWriter(file);
writer.append(content);
writer.flush();
writer.close();
//Toast.makeText(context, "Writing to the file completed successfully", Toast.LENGTH_LONG).show();
}catch (Exception e){
Toast.makeText(context, "File writing failed: " + e.toString(), Toast.LENGTH_LONG).show();
}
File filePath = new File(context.getCacheDir(), "");
File newFile = new File(filePath, fileName);
return FileProvider.getUriForFile(context, "MYPACKAGE.fileprovider", newFile);
}
}
and in another class:
private void sendFile(String nameFile, String logContent, String fileExtension) {
Uri contentUri = GenerateFile.getFileURI(getApplicationContext(), nameFile, logContent, fileExtension);
Intent intent = ShareCompat.IntentBuilder.from(StatusActivity.this)
.setStream(contentUri) // uri from FileProvider
.setType("text/plain")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intent, "send"));
}
so to send the file. I also deleted the permission (previously mentioned) in the manifest, because I didn't need it anymore.
And I also edited my provider and provider_path file like that:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="MYPACKAGE.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
<?xml version="1.0" encoding="utf-8"?>
<cache-path
name="my_files"
path=""
/>
Now it works! Thank you very much guys for the help!
Did you specifically ask the user for those permissions? It's not enough to just put the permissions in the manifest for target sdks below 28. Also, in Android Q, you will need to work around external storage permissions altogether as this is disallowed.
I have an option in my app that share image to whatsapp,facebook etc. For share image through intent, i want specific image from image view on which share button is clicked.
I have the following code that does not work.it share an empty file to whatsapp.
val shareBtn = findViewById<TextView>(R.id.share_btn)
val postImage = findViewById<ImageView>(R.id.post_image)
val path:String?=postImage.tag.toString()
val file= File(path)
shareBtn.setOnClickListener {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image"
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file))
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(Intent.createChooser(intent, "Share Image"))
First to store image of ImageView , you need to convert to Bitmap
val bitMap : Bitmap =imageview.getDrawingCache();
now store this image to file
val bos : ByteArrayOutputStream = ByteArrayOutputStream();
bitMap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
val file : File = File(Environment.getExternalStorageDirectory() + File.separator + "your_file.jpg");
try {
file.createNewFile();
val fos : FileOutputStream = FileOutputStream(file);
fos.write(bos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
now create an intent by specifying type 'image/jpeg'
and setting extra stream and path of the file that is to be shared
val intent= new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/your_file.jpg"));
And start Activity by creating chooser
startActivity(Intent.createChooser(intent, "Share Image"));
a great way for share image file ( Kotlin ) :
first create a folder named xml in the res folder and create a new XML Resource File named provider_paths.xml and put the below code inside it :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="."/>
<external-path
name="external_files"
path="."/>
</paths>
now go to the manifests folder and open the AndroidManifest.xml and then put the below code inside 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_paths.xml file path in this example
</provider>
now you put the below code in the setOnLongClickListener :
button.setOnLongClickListener {
try {
val file = File("pathOfFile")
if(file.exists()) {
val uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file)
val intent = Intent(Intent.ACTION_SEND)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setType("image/*")
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent)
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
toast("Error")
}
}
I am saving a file on internal storage. It is just a .txt file with some information about objects:
FileOutputStream outputStream;
String filename = "file.txt";
File cacheDir = context.getCacheDir();
File outFile = new File(cacheDir, filename);
outputStream = new FileOutputStream(outFile.getAbsolutePath());
outputStream.write(myString.getBytes());
outputStream.flush();
outputStream.close();
Then I am creating a "shareIntent" to share this file:
Uri notificationUri = Uri.parse("content://com.package.example/file.txt");
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, notificationUri);
shareIntent.setType("text/plain");
context.startActivity(Intent.createChooser(shareIntent, context.getResources().getText(R.string.chooser)));
The chosen app now needs access to the private file so I created a Content provider. I just changed the openFile method:
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File privateFile = new File(getContext().getCacheDir(), uri.getPath());
return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
The manifest:
<provider
android:name=".ShareContentProvider"
android:authorities="com.package.example"
android:grantUriPermissions="true"
android:exported="true">
</provider>
When opening the Mail App to share the file it says, that it could not attach the file because it only has 0 Bytes. Sharing it via Bluetooth also failed. But I can read out the privateFile in the Content Provider, so it exists and it has content. What is the problem?
Thanks for pskink. FileProvider worked perfectly:
Gradle dependency:
compile 'com.android.support:support-v4:25.0.0'
Manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.package.example"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
file_paths.xml in XML folder:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache" path="/" />
</paths>
Sharing Intent:
File file = new File(context.getCacheDir(), filename);
Uri contentUri = FileProvider.getUriForFile(context, "com.package.example", file);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.setType("text/plain");
context.startActivity(Intent.createChooser(shareIntent, context.getResources().getText(R.string.chooser)));