Gmail 5.0 app fails with “Permission denied for th

2020-01-25 00:47发布

My app creates mails with attachments, and uses an intent with Intent.ACTION_SEND to launch a mail app.

It works with all the mail apps I tested with, except for the new Gmail 5.0 (it works with Gmail 4.9), where the mail opens without attachment, showing the error: "Permission denied for the attachment".

There are no useful messages from Gmail on logcat. I only tested Gmail 5.0 on Android KitKat, but on multiple devices.

I create the file for the attachment like this:

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

I'm aware of the security concerns with MODE_WORLD_READABLE.

I send the intent like this:

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

Is there anything I do wrong when creating the file or sending the intent? Is there a better way to start a mail app with attachment? Alternatively - has someone encountered this problem and found a workaround for it?

Thanks!

9条回答
做个烂人
2楼-- · 2020-01-25 01:23

Google have an answer for that issue:

  • Store the data in your own ContentProvider, making sure that other apps have the correct permission to access your provider. The preferred mechanism for providing access is to use per-URI permissions which are temporary and only grant access to the receiving application. An easy way to create a ContentProvider like this is to use the FileProvider helper class.

  • Use the system MediaStore. The MediaStore is primarily aimed at video, audio and image MIME types, however beginning with Android 3.0 (API level 11) it can also store non-media types (see MediaStore.Files for more info). Files can be inserted into the MediaStore using scanFile() after which a content:// style Uri suitable for sharing is passed to the provided onScanCompleted() callback. Note that once added to the system MediaStore the content is accessible to any app on the device.

Also you can try set permissions for your file:

emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

And finally you can copy/store your files in external storage - permissions not needed there.

查看更多
你好瞎i
3楼-- · 2020-01-25 01:23

I was having this problem and finally found an easy way to send email with attachment. Here is the code

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();
    }
}

In this code "myPic" is bitmap which was returned by camera intent

查看更多
兄弟一词,经得起流年.
4楼-- · 2020-01-25 01:25

I tested it and I found out that it was definitely private storage access problem. When you attach some file to Gmail (over 5.0) do not use the file from private storage such as /data/data/package/. Try to use /storage/sdcard.

You can successfully attach your file.

查看更多
三岁会撩人
5楼-- · 2020-01-25 01:28

Use getExternalCacheDir() with File.createTempFile.

Use the following to create a temporary file in the external cache directory:

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

Then copy your original file's content to 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();

now put your file to intent,

emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
查看更多
ゆ 、 Hurt°
6楼-- · 2020-01-25 01:28

Step 1: Add authority in your attached URI

Uri uri = FileProvider.getUriForFile(context, ""com.yourpackage", file);

Same as your manifest file provide name

android:authorities="com.yourpackage"

Step 2`; Add flag for allow to read

myIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

查看更多
Summer. ? 凉城
7楼-- · 2020-01-25 01:29

I was able to pass a screenshot .jpeg file from my app to GMail 5.0 through an Intent. The key was in this answer.

Everything I have from @natasky 's code is nearly identical but instead, I have the file's directory as

context.getExternalCacheDir();

Which "represents the external storage directory where you should save cache files" (documentation)

查看更多
登录 后发表回答