Android调用Gmail发送JSON附件报permission denied for attachment如何解决
问题核心原因
你遇到的权限报错本质是第三方邮件应用(Gmail)没有权限访问你应用私有的内部存储文件,你给Intent加的读写权限标记对file://格式的Uri不生效,从Android 7.0开始系统也禁止跨应用传递file://格式的Uri,会直接触发暴露异常。
解决步骤
步骤1:在AndroidManifest.xml中配置FileProvider
在<application>标签内添加如下Provider配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
如果你的项目还在用旧版support库,把name属性值改成android.support.v4.content.FileProvider即可。
步骤2:创建file_paths.xml配置文件
在res目录下新建xml文件夹,在xml文件夹内新建file_paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应你应用内部存储的files目录,就是你存json文件的路径 --> <files-path name="internal_files" path="." /> </paths>
步骤3:修改发送邮件的代码,替换Uri生成逻辑
把原来硬编码路径+file://拼接的逻辑替换为用FileProvider生成的content类型Uri,修改后的代码如下:
sendgmailButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 不要硬写路径,用系统API获取内部存储路径更规范,兼容不同设备 File jsonFile = new File(getFilesDir(), "jsonexample.json"); // 这里的authorities要和Manifest里配置的保持一致 Uri fileUri = FileProvider.getUriForFile(view.getContext(), BuildConfig.APPLICATION_ID + ".fileprovider", jsonFile); Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); emailIntent.setType("application/json"); emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {"examplegmail@gmail.com"}); emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Test Subject"); emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "go on read the emails"); emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri); startActivity(Intent.createChooser(emailIntent, "Send mail...")); } });
额外优化点
- 你Manifest里申请的
WRITE_INTERNAL_STORAGE、READ_INTERNAL_STORAGE是无效权限,应用访问自己的内部存储不需要申请任何权限,可以直接删掉这两行配置。 - 如果你后续要读取外部存储的文件作为附件,Android 6.0及以上版本需要动态申请读写存储权限,当前你用的是内部存储不需要额外申请。
内容的提问来源于stack exchange,提问作者Muratcan Yıldız
相关产品推荐
相关产品推荐

