You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用flutter_email_sender发送文件真机失效问题排查求助

问题解决:Flutter真机无法通过Gmail发送PDF/Word文件

核心问题分析

模拟器环境对应用间交互的权限限制较宽松,但真机(尤其是Android 10+)受Scoped Storage和应用查询权限的约束,导致直接传递文件路径无法被Gmail访问,或无法触发Gmail的启动Intent。

分步解决方案

1. 补充AndroidManifest的应用查询权限

当前queries仅配置了SENDTO(用于无附件的邮件链接),但发送带附件的邮件需要SEND和SEND_MULTIPLE动作声明。修改AndroidManifest.xml的<queries>块:

<queries>
    <!-- 保留原有配置 -->
    <intent>
      <action android:name="android.intent.action.SENDTO" />
      <data android:scheme="mailto" />
    </intent>
    <!-- 添加以下两个intent -->
    <intent>
      <action android:name="android.intent.action.SEND" />
      <data android:mimeType="*/*" />
    </intent>
    <intent>
      <action android:name="android.intent.action.SEND_MULTIPLE" />
      <data android:mimeType="*/*" />
    </intent>
    <!-- 保留其他原有intent -->
</queries>

2. 处理Android 10+的Scoped Storage限制

真机上直接传递外部存储的文件路径会导致Gmail无权限访问,需要通过FileProvider生成可共享的Content Uri:

步骤1:注册FileProvider

在AndroidManifest.xml的<application>标签内添加:

<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>

步骤2:创建文件路径配置

在res/xml目录下新建file_paths.xml(无xml目录则手动创建):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="app_files" path="." />
    <external-path name="external_files" path="." />
</paths>

步骤3:修改发送逻辑

更新VacancyController的sendFile方法,复制文件到应用共享目录并生成Content Uri:

import 'package:path_provider/path_provider.dart';
import 'package:flutter/services.dart';

Future<String> sendFile() async {
  if (file != null) {
    try {
      // 将选中文件复制到应用可共享的外部存储目录
      final appExternalDir = await getExternalFilesDirectory(null);
      final fileName = file!.path.split('/').last;
      final copiedFile = await file!.copy('${appExternalDir!.path}/$fileName');

      // 生成Content Uri
      final contentUri = FileProvider.getUriForFile(
        Get.context!,
        '${Get.context!.packageName}.fileprovider',
        copiedFile,
      );

      final Email email = Email(
        body: 'CV- faylı bizimlə paylaşın!',
        subject: 'Vakansiya',
        recipients: ['ahmadovf@box.az'],
        attachmentPaths: [contentUri.toString()], // 传入Uri字符串
        isHTML: false,
      );

      await FlutterEmailSender.send(email);
      _file.value = null;
      // 清理临时文件
      await copiedFile.delete();
      return 'success';
    } catch (e) {
      print('发送错误详情: $e');
      return 'fail: ${e.toString()}';
    }
  }
  return 'fail';
}

3. 添加错误捕获排查问题

如果暂时不想修改FileProvider逻辑,先在sendFile中加入try-catch,打印真机上的具体错误,快速定位问题:

Future<String> sendFile() async {
  if (file != null) {
    try {
      final Email email = Email(
        body: 'CV- faylı bizimlə paylaşın!',
        subject: 'Vakansiya',
        recipients: ['ahmadovf@box.az'],
        attachmentPaths: [file!.path.toString()],
        isHTML: false,
      );

      await FlutterEmailSender.send(email);
      _file.value = null;
      return 'success';
    } catch (e) {
      print('发送失败原因: $e');
      return 'fail: ${e.toString()}';
    }
  }
  return 'fail';
}

4. Android 13+权限适配

如果真机是Android 13及以上,需要添加读取文档的权限到AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_MEDIA_DOCUMENTS" />

并在运行时通过permission_handler包请求该权限。


内容的提问来源于stack exchange,提问作者Farid Ahmadov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:12:11