首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 多附件郵件發送:ACTION_SEND_MULTIPLE 兼容性問題排查指南

     編輯:程式設計綜合問答

問題現象

使用 Intent.ACTION_SEND_MULTIPLE 發送帶多個附件的郵件,Gmail App 正常,但系統自帶「郵件」客戶端收到郵件無附件(正文、主題正常)。

代碼片段

Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"a@b.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "主題");
emailIntent.putExtra(Intent.EXTRA_TEXT, "正文");
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); // ArrayList
emailIntent.setType("text/plain");
startActivity(Intent.createChooser(emailIntent, "發送郵件"));

原因深度分析

  1. 不同客戶端對 Intent 解析邏輯不同:Gmail 完整實現了 ACTION_SEND_MULTIPLE;部分廠商/系統郵件客戶端僅處理 ACTION_SEND,忽略 EXTRA_STREAM 列表。
  2. Uri 權限問題:傳遞的 Uri 必須授予目標 App 讀取權限(FLAG_GRANT_READ_URI_PERMISSION),否則客戶端無法讀取文件內容。
  3. MIME 類型不匹配:setType("text/plain") 告訴系統這是純文本,附件類型應用 setType("*/*") 或具體類型(如 image/jpeg),並確保每個 Uri 對應正確 MIME。

修正方案

1. 授予 Uri 讀取權限(關鍵)

Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"a@b.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "主題");
emailIntent.putExtra(Intent.EXTRA_TEXT, "正文");

// 假設 uris 是 ArrayList,且來自 FileProvider
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);

// 關鍵:授予所有 Uri 讀取權限
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// 類型設置為通用或具體附件類型
emailIntent.setType("*/*"); // 或 "image/*", "application/pdf" 等
startActivity(Intent.createChooser(emailIntent, "發送郵件"));

2. 兼容舊版/非 FileProvider Uri

若 Uri 為 file:// 協議(Android 7.0+ 禁止跨應用暴露),必須遷移至 FileProvider 生成 content:// Uri。

3. 兜底:逐個發送或壓縮打包

若目標客戶端確不支持多附件,可:

  • 壓縮為單個 ZIP 文件,用 ACTION_SEND 發送。
  • 循環發送多個 ACTION_SEND(用戶體驗差,不推薦)。

源碼級驗證(參考 Android Email App)

// frameworks/opt/email/src/com/android/email/activity/Welcome.java 片段
if (Intent.ACTION_SEND_MULTIPLE.equals(action) && intent.hasExtra(Intent.EXTRA_STREAM)) {
    ArrayList list = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
    if (list != null) {
        for (Parcelable parcelable : list) {
            Uri uri = (Uri) parcelable;
            if (uri != null) {
                addAttachmentFromSendIntent(uri); // 內部會檢查 MIME、權限
            }
        }
    }
}

private void addAttachmentFromSendIntent(Uri uri) {
    Attachment attachment = loadAttachmentInfo(uri); // 解析 MIME、大小
    String mimeType = attachment.mMimeType;
    // 關鍵過濾:只接受白名單類型
    if (!TextUtils.isEmpty(mimeType) && MimeUtility.mimeTypeMatches(mimeType, ACCEPTABLE_ATTACHMENT_SEND_INTENT_TYPES)) {
        addAttachment(attachment);
    }
}

可見系統郵件客戶端會過濾 MIME 類型,若附件類型不在白名單(ACCEPTABLE_ATTACHMENT_SEND_INTENT_TYPES)中,會被靜默丟棄。

最佳實踐清單

  1. 使用 FileProvider 生成 content:// Uri。
  2. 調用 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)。
  3. 設置正確 MIME:setType("*/*") 或遍歷附件設置 intent.setType(mimeType)(單附件時)。
  4. 確保附件文件真實存在、可讀、大小合理。
  5. 測試覆蓋:Gmail、Outlook、系統郵件、廠商郵件(小米、華為、OPPO 等)。

總結

多附件郵件發送失效多因 Uri 權限缺失 或 MIME 類型被客戶端過濾。規範使用 FileProvider、授予權限、設置通用 MIME,可解決 90% 兼容性問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved