SAF - 使用 ACTION_CREATE_DOCUMENT 创建后通过邮件共享文件
Posted
技术标签:
【中文标题】SAF - 使用 ACTION_CREATE_DOCUMENT 创建后通过邮件共享文件【英文标题】:SAF - Share file via mail after creation with ACTION_CREATE_DOCUMENT 【发布时间】:2021-03-23 17:52:47 【问题描述】:我将我的 targetSdkVersion 更新为 30,因此我必须使用 SAF(存储访问框架)更新我的创建文件。
我能够创建文件、选择位置、获取 Uri 结果(格式为 content://),但是当我尝试将文件作为附件发送时,文件未附加。例如,Gmail 会显示一条消息“无法附加文件”。
我错过了什么吗?
任何帮助将不胜感激。谢谢大家
这是我的代码:
int WRITE_REQUEST_CODE = 336;
private void createFile()
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_TITLE, "dettaglio_utente.pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, WRITE_REQUEST_CODE);
private void alterDocument(Uri uri)
try
ParcelFileDescriptor pfd = getContentResolver().
openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream =
new FileOutputStream(pfd.getFileDescriptor());
byte[] pdfAsBytes = Base64.decode(pdfBase64, 0);
fileOutputStream.write(pdfAsBytes);
// Let the document provider know you're done by closing the stream.
fileOutputStream.close();
pfd.close();
catch (FileNotFoundException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
if (resultCode == RESULT_OK && requestCode == WRITE_REQUEST_CODE)
try
if (data != null && data.getData() != null)
Uri path = data.getData();
alterDocument(path);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setData(Uri.parse("mailto:")); // only email apps should handle this
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.privacy_mail_subject));
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.privacy_mail_body));
intent.putExtra(Intent.EXTRA_STREAM, path);
if (intent.resolveActivity(getPackageManager()) != null)
startActivity(intent);
catch (Exception e)
Toast.makeText(this, "something went wrong" + e.getMessage(), Toast.LENGTH_SHORT).show();
e.printStackTrace();
我还在 Manifest 中添加了 DocumentProvider,如 android 文档 StorageProvider 所示
<provider
android:name=".MyDocumentProvider"
android:authorities="$applicationId.documents"
android:enabled="true"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
【问题讨论】:
【参考方案1】:当您提供Uri
给其他人时,您添加FLAG_GRANT_READ_URI_PERMISSION
和/或FLAG_GRANT_READ_URI_PERMISSION
。
所以,关于你的代码:
您可以从您的createFile()
方法中删除intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
,因为您希望接收 Uri
在使用Intent
之前,您需要将intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
添加到您的ACTION_SEND
Intent
,因为您希望提供一个Uri
,并且您希望收件人能够读取那个Uri
标识的内容
还有:
从您的 <provider>
中删除 android:permission="android.permission.MANAGE_DOCUMENTS"
,因为其他应用(例如 Gmail)很可能不会拥有该权限
请注意,如果不在清单中添加 <queries>
元素,resolveActivity()
可能无法在 Android 11+ 上运行 - 您可能希望跳过 resolveActivity()
调用,只需将 startActivity()
调用包装在 try
/ 中catch
和处理ActivityNotFoundException
【讨论】:
感谢@CommonsWare 的回复,我删除了android:permission="android.permission.MANAGE_DOCUMENTS"
,但它在启动时给了我SecurityException。所以我这样解决:我从 Manifest 中删除了所有节点 <provider>
,然后我从电子邮件意图 intent.setData(Uri.parse("mailto:"));
中删除了以下行,并将其替换为 intent.setType("message/rfc822");
现在它可以工作了!!以上是关于SAF - 使用 ACTION_CREATE_DOCUMENT 创建后通过邮件共享文件的主要内容,如果未能解决你的问题,请参考以下文章
SAF(Storage Access Framework)使用攻略
在 Android 中从 File Api 迁移到 Storage Access Framework (SAF)