Android中如何正确获取Uri/String并转换为ByteString用于邮件附件?
解决Android中Content Uri转字节数组用于邮件附件的问题
核心问题分析
你之前的错误点:
- 直接把Content Uri的字符串文本转成输入流,读取的是Uri本身的字节,而非文件实际内容,所以生成1KB的无效文件。
getRealPathFromURI依赖MediaStore.Images.Media.DATA字段,在Android 10(API 29)及以上的**分区存储(Scoped Storage)**机制下,该字段可能返回空或无效路径,无法再通过这种方式获取真实文件路径。
正确解决方案:用ContentResolver统一处理所有Uri
Android官方推荐使用ContentResolver直接打开任何合法Uri(包括file://和content://类型)对应的输入流,无需区分Uri类型,这是兼容全版本的标准方案。
完整代码实现
import android.content.Context import android.net.Uri import android.util.Base64 import java.io.InputStream // 通用方法:将Uri转换为Base64字符串 fun uriToBase64(context: Context, uri: Uri): String? { return runCatching { context.contentResolver.openInputStream(uri)?.use { inputStream -> val bytes = inputStream.readBytes() Base64.encodeToString(bytes, Base64.DEFAULT) } }.getOrNull() } // 生成邮件附件JSON的方法 fun createAttachmentJson(context: Context, uri: Uri, currentDate: String, index: Int): String? { val base64Content = uriToBase64(context, uri) ?: return null val mimeType = context.contentResolver.getType(uri) ?: "image/jpeg" val filename = "IMAGE_${currentDate}_$index.jpg" return """ { "content": "$base64Content", "filename": "$filename", "type": "$mimeType", "disposition": "attachment" } """.trimIndent() }
代码说明
uriToBase64方法:- 通过
contentResolver.openInputStream(uri)获取文件输入流,这是处理Content Uri的标准方式。 - 用
use块自动关闭流,避免资源泄漏。 - 捕获异常并返回null,保证程序稳定性。
- 通过
createAttachmentJson方法:- 通过
contentResolver.getType(uri)自动获取文件的MIME类型,比硬编码更准确。 - 生成符合要求的附件JSON字符串。
- 通过
使用示例
处理PhotoPicker返回的Uri列表:
val uris: List<Uri> = // 从PhotoPicker获取的Uri列表 val currentDate = "2023-08-15" uris.forEachIndexed { index, uri -> val attachmentJson = createAttachmentJson(context, uri, currentDate, index) attachmentJson?.let { // 将该JSON添加到邮件附件列表 } }
额外注意事项
- 权限:确保应用已申请必要权限,Android 10以下需
READ_EXTERNAL_STORAGE,Android 13及以上需READ_MEDIA_IMAGES。 - 大文件优化:如果处理超大图片,
readBytes()可能占用过多内存,建议分块读取并编码Base64,避免OOM。
内容的提问来源于stack exchange,提问作者user21300258
相关产品推荐
相关产品推荐

