Gmail 5.0应用程序失败,其中"附件权限被拒绝"当它收到ACTION_SEND意图时

时间:2014-11-12 09:19:10

标签: android android-intent

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

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

在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);

我了解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);
}

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

谢谢!

9 个答案:

答案 0 :(得分:28)

我能够通过Intent将我的应用程序中的屏幕截图.jpeg文件传递给GM​​ail 5.0。关键是this answer

我从@natasky代码获得的所有内容几乎完全相同,但我将文件目录作为

context.getExternalCacheDir();

其中"表示应保存缓存文件的外部存储目录" (文档)

答案 1 :(得分:25)

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

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

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

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

TL; DR回答: 将startActivity替换为startActivityForResult。

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

答案 2 :(得分:14)

getExternalCacheDir()File.createTempFile一起使用。

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

File tempFile = File.createTempFile("fileName", ".txt", context.getExternalCacheDir());

然后将原始文件的内容复制到tempFile

FileWriter fw = new FileWriter(tempFile);

FileReader fr = new FileReader(Data.ERR_BAK_FILE);
int c = fr.read();
while (c != -1) {
    fw.write(c);
    c = fr.read();
}
fr.close();

fw.flush();
fw.close();

现在将你的文件置于意图,

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

答案 3 :(得分:5)

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

fileProvider.getUriForFile(attachment);

答案 4 :(得分:4)

Google对该问题有answer

  • 将数据存储在您自己的ContentProvider中,确保其他应用具有访问您的提供商的正确权限。提供访问的首选机制是使用临时的per-URI permissions,并且只授予对接收应用程序的访问权限。创建这样的ContentProvider的简单方法是使用FileProvider帮助程序类。

  • 使用系统MediaStoreMediaStore主要针对视频,音频和图片MIME类型,但从Android 3.0(API级别11)开始,它还可以存储非媒体类型(有关详细信息,请参阅MediaStore.Files)。可以使用MediaStore将文件插入scanFile(),之后将适合共享的content://样式Uri传递给提供的onScanCompleted()回调。请注意,一旦添加到系统MediaStore,设备上的任何应用都可以访问该内容。

您也可以尝试set permissions获取文件:

emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

最后,您可以将文件复制/存储在外部存储中 - 不需要权限。

答案 5 :(得分:3)

我测试了它,我发现它肯定是私有存储访问问题。 将某些文件附加到Gmail(超过5.0)时,请不要使用私有存储中的文件,例如/ data / data / package /。尝试使用/ storage / sdcard。

您可以成功附加文件。

答案 6 :(得分:2)

不确定为什么GMail 5.0不喜欢某些文件路径(我已经确认它确实具有读访问权限),但显然更好的解决方案是实现自己的ContentProvider类来提供文件。这实际上有点简单,我在这里找到了一个不错的例子:http://stephendnicholas.com/archives/974

请务必将标记添加到您的应用清单中,并在其中包含“android:grantUriPermissions =”true“”。您还需要实现getType()并为文件URI返回适当的MIME类型,否则某些应用程序将无法使用此...在链接的注释部分中有一个示例。

答案 7 :(得分:1)

我遇到了这个问题,终于找到了一种简单的方法来发送带附件的电子邮件。这是代码

public void SendEmail(){
    try {

        //saving image
        String randomNameOfPic = Calendar.DAY_OF_YEAR+DateFormat.getTimeInstance().toString();
        File file = new File(ActivityRecharge.this.getCacheDir(), "slip"+  randomNameOfPic+ ".jpg");
        FileOutputStream fOut = new FileOutputStream(file);
        myPic.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
        fOut.flush();
        fOut.close();
        file.setReadable(true, false);

        //sending email
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"zohabali5@gmail.com"});
        intent.putExtra(Intent.EXTRA_SUBJECT, "Recharge Account");
        intent.putExtra(Intent.EXTRA_TEXT, "body text");

        //Uri uri = Uri.parse("file://" + fileAbsolutePath);
        intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivityForResult(Intent.createChooser(intent, "Send email..."),12);
    }catch (Exception e){
        Toast.makeText(ActivityRecharge.this,"Unable to open Email intent",Toast.LENGTH_LONG).show();
    }
}

在此代码中,“myPic”是由相机意图返回的位图

答案 8 :(得分:0)

步骤1:在附加的URI中添加权限

Uri uri = FileProvider.getUriForFile(上下文,“” com.yourpackage“,文件);

与清单文件中的名称相同

android:authorities =“ com.yourpackage”

步骤2`;添加标记以允许读取

myIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);