Android的 ACTION_SEND意图:在将PDF附件保存到Gmail草稿箱或发送时会丢失
我正在编写一个Android应用,动态生成一个简单的PDF,然后通过一个Intent打开邮件客户端(如Gmail),并附上收件人、主题、正文以及PDF附件。
问题: Intent成功打开应用选择器,当我选择Gmail时,撰写界面会完美打开。“To”、“Subject”、“Body”以及PDF附件都在撰写界面中可见。
然而,当我点击“Send”时,它并不会真正发送。它直接跳转到草稿箱,且PDF附件不见了。只有纯文本保留。
我尝试过的做法(都无效): 为了根据现代Android(API 30+)的最佳实践解决这个问题,我尝试了以下方法:
- 使用
FileProvider来正确提供content://URI,而不是file://URI。 - 在intent中添加
Intent.FLAG_GRANT_READ_URI_PERMISSION。 - 添加
intent.setClipData(ClipData.newRawUri("PDF", uri)),这是某些现代应用查看附件所必需的。 - 试着使用
ShareCompat.IntentBuilder以确保Intent构造得无可挑剔。 - 测试将PDF保存到多个位置:
getCacheDir()、getExternalCacheDir()和getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)。 - 在
FileOutputStream中添加fos.getFD().sync(),以确保在触发Intent之前PDF已完全写入到物理磁盘。 - 在Android 11+的包可见性配置中,为Manifest添加
<queries>用于<action android:name="android.intent.action.SEND" />。 - 为每个PDF使用
System.currentTimeMillis()生成唯一文件名,以确保Gmail不会缓存旧的/损坏的草稿。
尽管如此,附件仍然在后台悄悄地丢失。
我的代码:
`MainActivity.java`
public class MainActivity extends AppCompatActivity {
private static final String RECIPIENT = "[email protected]";
private static final String SUBJECT = "Test Email";
private static final String BODY = "Test Email";
private static final String FILE_PROVIDER_AUTHORITY = "com.mike.email.fileprovider";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnEmailPDF).setOnClickListener(v -> sendEmailWithPdf());
}
private void sendEmailWithPdf() {
File pdfFile = createPdf();
if (pdfFile == null || !pdfFile.exists()) return;
Uri contentUri = FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, pdfFile);
Intent intent = ShareCompat.IntentBuilder.from(this)
.setType("application/pdf")
.setEmailTo(new String[]{RECIPIENT})
.setSubject(SUBJECT)
.setText(BODY)
.setStream(contentUri)
.getIntent();
// Granting permissions
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setClipData(ClipData.newRawUri("PDF Attachment", contentUri));
startActivity(Intent.createChooser(intent, "Send Email with PDF..."));
}
private File createPdf() {
PdfDocument document = new PdfDocument();
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(595, 842, 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
Canvas canvas = page.getCanvas();
Paint paint = new Paint();
paint.setTextSize(18);
canvas.drawText("Hello, this is a test PDF document.", 50, 50, paint);
document.finishPage(page);
File baseDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File directory = new File(baseDir, "EmailTests");
if (!directory.exists()) directory.mkdirs();
// Unique filename
File file = new File(directory, "EmailTest_" + System.currentTimeMillis() + ".pdf");
try (FileOutputStream fos = new FileOutputStream(file)) {
document.writeTo(fos);
fos.flush();
fos.getFD().sync(); // Ensure physical write
} catch (IOException e) {
return null;
} finally {
document.close();
}
return file;
}
}
`AndroidManifest.xml`
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="application/pdf" />
</intent>
</queries>
<application ...>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.mike.email.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
`res/xml/file_paths.xml`
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="my_pdfs" path="Documents/EmailTests" />
</paths>
是否存在一个已知问题:在较新版本Android上 Gmail会丢弃FileProvider附件,还是我在intent委托中遗漏了某个边缘情况?任何帮助都将不胜感激!
解决方案
你在构建 Intent 的工作中使用了 setStream() 作为 ShareCompat.IntentBuilder 的一部分。随后你通过调用 setClipData() 修改了 Intent… 这正是 ShareCompat.IntentBuilder 的作用。我的猜测是你对 setClipData() 的调用干扰了 ShareCompat.IntentBuilder 的运作,因此移除此调用后得到的结果会更稳定。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。