Android Studio中FileProvider实现txt邮件附件分享Android11失效问题求助
解决方案
一、Android 11 上Intent唤起邮箱发附件失效问题修复
你遇到的兼容问题是API 30+权限规则变更、路径映射错误、Intent写法不规范共同导致的,按以下步骤修改即可:
1. 移除无效的存储权限配置
Android 11(API 30)开始,WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE权限已废弃,你使用的getExternalFilesDir属于应用专属外部存储,不需要申请任何存储权限:
- 删除
onCreate里的存储权限申请代码 - 删除
AndroidManifest.xml里的存储权限声明
2. 修正file_paths.xml路径映射配置
你之前配置的<external-path>对应系统公共存储根目录,和你实际存储文件用的getExternalFilesDir路径不匹配,Android 11对路径校验更严格所以触发异常,修改为以下配置即可:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应getExternalFilesDir("AppData")的路径,name为URI别名可自定义 --> <external-files-path name="app_shared_files" path="AppData/" /> </paths>
3. 优化文件保存逻辑
修正原有代码里的冗余逻辑和文件名笔误:
private String SaveToExternal(String fileContent) { if (fileContent.isEmpty()) { Toast.makeText(this, "没有可保存的数据", Toast.LENGTH_SHORT).show(); return null; } File appDir = getExternalFilesDir("AppData"); if (appDir == null) { Toast.makeText(this, "存储不可用", Toast.LENGTH_SHORT).show(); return null; } // 目录不存在则创建 if (!appDir.exists()) { appDir.mkdirs(); } File targetFile = new File(appDir, "DataToSend.txt"); try (FileOutputStream fos = new FileOutputStream(targetFile)) { fos.write(fileContent.getBytes(StandardCharsets.UTF_8)); Toast.makeText(this, "文件准备完成", Toast.LENGTH_SHORT).show(); return targetFile.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "文件保存失败", Toast.LENGTH_SHORT).show(); return null; } }
4. 修正邮件发送Intent写法
ACTION_SENDTO搭配mailto协议的方式本身不支持附件,旧系统能运行是厂商做了兼容,Android 11上的邮箱应用都遵循官方规范所以失效,修改为以下代码:
private void sendEmail(String Body, String FilePath) { if (FilePath == null) return; File file = new File(FilePath); if (!file.exists()) { Toast.makeText(this, "附件不存在", Toast.LENGTH_SHORT).show(); return; } try { Uri fileUri = FileProvider.getUriForFile(this, "com.example.XXXX.YYYY", file); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("message/rfc822"); intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"XYZ@gmail.com"}); intent.putExtra(Intent.EXTRA_SUBJECT, "邮件主题"); intent.putExtra(Intent.EXTRA_TEXT, "尊敬的先生/女士\n\n我想要......"); intent.putExtra(Intent.EXTRA_STREAM, fileUri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Intent chooser = Intent.createChooser(intent, "选择邮件应用发送"); // 给所有匹配的应用授予URI读取权限 List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); } startActivity(chooser); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "未找到可用的邮件应用", Toast.LENGTH_SHORT).show(); } }
5. 按钮调用逻辑优化
增加路径非空判断避免空指针:
String rv = "需要保存为文本文件并作为附件发送的测试内容"; String dataPathFile = SaveToExternal(rv); if (dataPathFile != null) { sendEmail(rv, dataPathFile); }
二、后台直接发送带附件Gmail的实现教程
你之前找到的“允许低安全级别访问”的方案已经在2022年被谷歌全面禁用,现在只能通过Gmail API + OAuth2认证实现,步骤如下:
- 谷歌云控制台配置:创建新项目,开启Gmail API,创建OAuth客户端ID,填写应用包名和SHA1签名(开发版、发布版都要填),下载
google-services.json放到app模块根目录 - 依赖配置:项目根目录
build.gradle添加谷歌服务插件依赖,app模块build.gradle引入Gmail API、谷歌认证相关依赖 - 代码实现:先引导用户登录谷歌账号授权Gmail发送权限,构建带附件的MIME邮件转Base64URL编码,调用Gmail API的
users.messages.send接口发送
注意:该方案需要用户主动授权,无法在用户无感知的情况下后台发邮件,违反规则会被谷歌封禁账号
内容的提问来源于stack exchange,提问作者user2573266
相关产品推荐
相关产品推荐

