Gmail 5.0应用在收到ACTION_SEND意图时失败并显示"附件权限被拒绝"

nat*_*sky 41 android android-intent

我的应用程序创建带附件的邮件,并使用意图Intent.ACTION_SEND来启动邮件应用程序.

它适用于我测试过的所有邮件应用,除了新的Gmail 5.0(适用于Gmail 4.9),邮件打开时没有附件,显示错误:"附件权限被拒绝".

在logcat上没有来自Gmail的有用消息.我只测试了Android KitKat上的Gmail 5.0,但是在多个设备上.

我为附件创建了这样的文件:

String fileName = "file-name_something_like_this";
FileOutputStream output = context.openFileOutput(
        fileName, Context.MODE_WORLD_READABLE);

// Write data to output...

output.close();
File fileToSend = new File(context.getFilesDir(), fileName);
Run Code Online (Sandbox Code Playgroud)

我知道安全问题MODE_WORLD_READABLE.

我发送这样的意图:

public static void compose(
        Context context,
        String address,
        String subject,
        String body,
        File attachment) {

    Intent emailIntent = new Intent(Intent.ACTION_SEND);
    emailIntent.setType("message/rfc822");
    emailIntent.putExtra(
            Intent.EXTRA_EMAIL, new String[] { address });
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
    emailIntent.putExtra(Intent.EXTRA_TEXT, body);

    emailIntent.putExtra(
            Intent.EXTRA_STREAM,
            Uri.fromFile(attachment));

    Intent chooser = Intent.createChooser(
            emailIntent, 
            context.getString(R.string.send_mail_chooser));

    context.startActivity(chooser);
}
Run Code Online (Sandbox Code Playgroud)

在创建文件或发送意图时,我有什么问题吗?有没有更好的方法来启动带附件的邮件应用程序?或者 - 有人遇到这个问题,并找到了解决方法吗?

谢谢!

c0d*_*ded 28

我能够通过Intent将截屏.jpeg文件从我的应用程序传递到GMail 5.0.关键在于这个答案.

我从@natasky的代码中得到的一切几乎相同,但我将文件的目录作为

context.getExternalCacheDir();
Run Code Online (Sandbox Code Playgroud)

哪个"代表应保存缓存文件的外部存储目录"(文档)

  • 这样做对我来说.我实际上使用的是`File.createTempFile`,它接受该位置的第三个参数.我为第三个参数传递了`activity.getExternalCacheDir()`,一切都运行得很漂亮.谢谢! (3认同)

And*_* Id 26

GMail 5.0为从Intent接收的附件添加了一些安全检查.这些与unix权限无关,因此文件可读的事实并不重要.

当附件Uri是file://时,它只接受来自外部存储的文件,gmail本身的私人目录或来自调用应用程序的私有数据目录的世界可读文件.

这种安全检查的问题在于它依赖于gmail能够找到调用者应用程序,这只有在调用者请求结果时才可靠.在上面的代码中,您不会要求结果,因此gmail不知道调用者是谁,并拒绝您的文件.

因为它适用于4.9而不是5.0,所以你知道它不是unix权限问题,所以原因必须是新的检查.

TL; DR回答: 用startActivityForResult替换startActivity.

或者更好的是,使用内容提供商.

  • 我尝试这个时仍然得到一个允许拒绝吐司.也许内容提供商是唯一的出路 (6认同)

Jos*_*ter 16

使用getExternalCacheDir()File.createTempFile.

使用以下命令在外部缓存目录中创建临时文件:

File tempFile = File.createTempFile("fileName", ".txt", context.getExternalCacheDir());
Run Code Online (Sandbox Code Playgroud)


Mil*_*ský 5

您应该实现一个FileProvider,它可以为您应用的内部文件创建Uris.其他应用程序被授予阅读这些Uris的权限.然后,只需调用Uri.fromFile(attachment),就可以实例化FileProvider并使用:

fileProvider.getUriForFile(attachment);
Run Code Online (Sandbox Code Playgroud)