kotlin 发送带附件的电子邮件因 URI 失败
kotlin send email with attachment fails with URI
我有以下 kotlin 代码来发送带附件的电子邮件:
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)
现在,当我运行上面的代码时,我得到一个错误:
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
为 fileURI 赋值行。如果不是 FileProvider,如果我使用:
putExtra(Intent.EXTRA_STREAM, file!!.toURI())
作为额外的意图参数,然后我得到一个错误:
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:尝试转换生成的内部异常:
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)
该文件是在全局 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
目录下的子目录下创建的,应用程序也具有 Manifest.permission.WRITE_EXTERNAL_STORAGE
权限。关于如何获取文件的 URI 并将其附加到电子邮件意图的任何指示?
对于您的第一次尝试——这是正确的方法——您的 <provider>
没有 com.mydomain.myapp
的权限值。清单中 <provider>
元素中的权限字符串必须与您传递给 getUriForFile()
的第二个参数相匹配。 the documentation for FileProvider
.
中对此进行了介绍
第二次尝试,toURI()
returns URI
,而不是 Uri
。虽然您可以将其切换为 Uri.fromFile()
,但一旦您的 targetSdkVersion
攀升至 24 或更高,您将在 Android 7.0+ 上崩溃。使用 FileProvider
方法。
使用以下代码在 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("asd@gmail.com")
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..."))
}
实施
清单:
<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>
使用 Sankar 的实现,但要获取文件 uri,权限必须等于清单中声明的权限:
val fileURI = FileProvider.getUriForFile(context, "$packageName.fileprovider", yourFile)
我有以下 kotlin 代码来发送带附件的电子邮件:
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)
现在,当我运行上面的代码时,我得到一个错误:
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
为 fileURI 赋值行。如果不是 FileProvider,如果我使用:
putExtra(Intent.EXTRA_STREAM, file!!.toURI())
作为额外的意图参数,然后我得到一个错误:
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:尝试转换生成的内部异常:
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)
该文件是在全局 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
目录下的子目录下创建的,应用程序也具有 Manifest.permission.WRITE_EXTERNAL_STORAGE
权限。关于如何获取文件的 URI 并将其附加到电子邮件意图的任何指示?
对于您的第一次尝试——这是正确的方法——您的 <provider>
没有 com.mydomain.myapp
的权限值。清单中 <provider>
元素中的权限字符串必须与您传递给 getUriForFile()
的第二个参数相匹配。 the documentation for FileProvider
.
第二次尝试,toURI()
returns URI
,而不是 Uri
。虽然您可以将其切换为 Uri.fromFile()
,但一旦您的 targetSdkVersion
攀升至 24 或更高,您将在 Android 7.0+ 上崩溃。使用 FileProvider
方法。
使用以下代码在 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("asd@gmail.com")
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..."))
}
实施
清单:
<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>
使用 Sankar 的实现,但要获取文件 uri,权限必须等于清单中声明的权限:
val fileURI = FileProvider.getUriForFile(context, "$packageName.fileprovider", yourFile)