Android11:发送带有自动附加文件的电子邮件

Android 11: Send e-mail with automatically attached file

我想要打开和电子邮件应用程序,其中包含已生成的文本、主题、收件人和附件,它适用于 android SDK 版本 29(android 10)及更低版本。但是从Android 11开始有限制写入外部或内部存储文件,还有另一个限制是不允许从应用程序文件目录自动附加文件。 以前我是从应用程序存储复制到内部或外部存储以附加文件,有什么解决方案吗?

完成 android:requestLegacyExternalStorage="true"

public static void sendMail(Context context) throws IOException {
        Context appContext = context.getApplicationContext();

        File logFile = FileUtils.createFile(context.getFilesDir().getAbsolutePath(), "testFile.txt", "Test");

        File logsDirectory = new File(FileUtils.getStorageDirectory(appContext), "files");
        logsDirectory.mkdirs();

        File destFile = new File(logsDirectory, "log.txt");

        InputStream in = new FileInputStream(logFile);
        boolean copied = FileUtils.copyToFile(in, destFile);

        Uri logPath = Uri.fromFile(destFile);

        Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
        emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // set the type to 'email'
        emailIntent.setData(Uri.parse("mailto:"));
        String[] to = {"support@test.com"};
        String subject = "Test log";
        String body =
                "Hello";
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
        // the attachment
        emailIntent.putExtra(Intent.EXTRA_STREAM, logPath);

        context.startActivity(Intent.createChooser(emailIntent, "Send email..."));
    } 
public class FileUtils {
    
        public static String getExtensionFromFileName(String fileName) {
        if (fileName == null) return null;

        String extension = null;
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            extension = fileName.substring(i + 1);
        }
        return extension;
    }

    /**
     * Copy data from a source stream to destFile. Return true if succeed, return false if failed.
     */
    public static boolean copyToFile(InputStream inputStream, File destFile) {
        if (inputStream == null || destFile == null) return false;
        try {
            try (OutputStream out = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            }
            return true;
        } catch (IOException e) {
            Log.e("[File Utils]", "copyToFile exception: " + e);

        }
        return false;
    }


    public static String getStorageDirectory(Context mContext) {
        String storageDir =
                Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/"
                        + mContext.getString(R.string.app_name);
        File file = new File(storageDir);
        mContext.getExternalMediaDirs();

        if (!file.isDirectory() || !file.exists()) {


        }
        return storageDir;
    }

    public static File createFile(String directory ,String fileName, String textToAttach)
    {
        File logFile = new File(directory  + "/" + fileName);
        if (!logFile.exists())
        {
            try
            {
                logFile.createNewFile();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try
        {
            //BufferedWriter for performance, true to set append to file flag
            BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
            buf.append(textToAttach);
            buf.newLine();
            buf.close();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return logFile;
    }
}

我已经使用了 FileProvider 和选择器,这是针对多个文件的

public static void sendMail(Context context) {
        Context appContext = context.getApplicationContext();
        final String authority = appContext.getPackageName() + ".FileProvider";
        String[] to = {"test@test.com"};
        String subject = "subject";
        String body = "body";
        
        ArrayList<File> logFiles = getLogFile(context);

        if (logFiles.size() == 0) {
            Toast.makeText(
                            context,
                            context.getString(R.string.toast_send_failed_no_file_found),
                            Toast.LENGTH_LONG)
                    .show();
            return;
        }
        // has to be an ArrayList

        ArrayList<Uri> logPaths = new ArrayList<>();
        for (File file : logFiles) {
            if (file.exists()) {
                logPaths.add(FileProvider.getUriForFile(appContext, authority, file));
            }
        }

        Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
        emailSelectorIntent.setDataAndType(Uri.parse("mailto:"), "plain/text");

        final Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        // emailIntent.setType("plain/text");
        emailIntent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_TEXT, body);
        emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, logPaths);
        emailIntent.setSelector(emailSelectorIntent);

        context.startActivity(Intent.createChooser(emailIntent, "Send Logs"));
    }