2

I have the following kotlin code to send an email with an attachment:

val file = File(directory, filename)
file.createNewFile()
file.writeText("My Text", Charsets.UTF_8)
// ---- file is written succesfully, now let us
// try to get the URI and pass it for the intent

val fileURI = FileProvider.getUriForFile(this, "com.mydomain.myapp", file!!)

val emailIntent = Intent(Intent.ACTION_SEND).apply {
        putExtra(Intent.EXTRA_SUBJECT, "My subject"))
        putExtra(Intent.EXTRA_TEXT, "My message")
        putExtra(Intent.EXTRA_STREAM, fileURI)
    }
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.type = "text/plain"
startActivity(emailIntent)

Now, when I run the above code, I get an error:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

for the fileURI assignment line. If instead of FileProvider, if I use:

putExtra(Intent.EXTRA_STREAM, file!!.toURI())

as the extra intent parameter, then I get an error:

W/Bundle: Key android.intent.extra.STREAM expected Parcelable but value was a java.net.URI.  The default value <null> was returned.

03-22 11:39:06.625 9620-9620/com.secretsapp.secretsapp W/Bundle: Attempt to cast generated internal exception:

W/Bundle: Key android.intent.extra.STREAM expected Parcelable but value was a java.net.URI.  The default value <null> was returned.
   W/Bundle: Attempt to cast generated internal exception:
   java.lang.ClassCastException: java.net.URI cannot be cast to android.os.Parcelable
   at android.os.Bundle.getParcelable(Bundle.java:945)

The file is created under a sub-directory under the global Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) directory and the app has Manifest.permission.WRITE_EXTERNAL_STORAGE permission too. Any pointers on how I can get the URI for the file and attach it to the email intent ?

3 Answers 3

2

For your first attempt — which is the correct approach — your <provider> does not have an authority value of com.mydomain.myapp. The authority string in the <provider> element in the manifest must match the 2nd parameter that you pass to getUriForFile(). This is covered in the documentation for FileProvider.

For your second attempt, toURI() returns a URI, not a Uri. While you could switch that to Uri.fromFile(), you will then crash on Android 7.0+, once your targetSdkVersion climbs to 24 or higher. Use the FileProvider approach.

Sign up to request clarification or add additional context in comments.

1 Comment

I have got it working. I have totally ignored the <provider> tag. After a bit of a frantic googling, I found it. Thanks. I am marking this as the accepted answer, however May be you could paste some code (of the manifest) so that it would be useful for people who come looking for a solution ?
1

Implementation of CommonsWare's answer

manifest:

<application> 
...
<provider
            android:name="android.support.v4.content.FileProvider" <- or use your provider implementation
            android:authorities="com.your.package.fileprovider" <- must end with .fileprovider
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
...
</application

res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path path="Android/data/" name="files_root" />
    <external-path path="." name="external_storage_root" />
</paths>

Use Sankar' implementation, but to get file uri, authority must equal the one declared in manifest:

val fileURI = FileProvider.getUriForFile(context, "$packageName.fileprovider", yourFile)

Comments

0

Use below code for send email with intent in Kotlin:

private fun sendEmail() {
    val filename = "contacts_sid.vcf"
    val filelocation = File(Environment.getExternalStorageDirectory().getAbsolutePath(), filename)
    val path = Uri.fromFile(filelocation)
    val emailIntent = Intent(Intent.ACTION_SEND)
    // set the type to 'email'
    emailIntent.type = "vnd.android.cursor.dir/email"
    val to = arrayOf("[email protected]")
    emailIntent.putExtra(Intent.EXTRA_EMAIL, to)
    // the attachment
    emailIntent.putExtra(Intent.EXTRA_STREAM, path)
    // the mail subject
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject")
    startActivity(Intent.createChooser(emailIntent, "Send email..."))
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.