"Permission denied for the attachment"(在 Gmail 5.0 上)尝试将文件附加到电子邮件意图

"Permission denied for the attachment" (on Gmail 5.0) trying to attach file to email intent

此问题之前已发布,但没有明确或公认的答案,并且提供的所有解决方案都应该 "work" 不适合我。看这里:Gmail 5.0 app fails with "Permission denied for the attachment" when it receives ACTION_SEND intent

我有一个在文本文件中构建数据的应用程序,需要在电子邮件中发送文本文件,并自动附加它。我已经尝试了很多方法来附加它,它显然适用于 Gmail 4.9 及以下版本,但 5.0 有一些新的权限功能,无法执行我希望的操作。

    Intent i = new Intent(Intent.ACTION_SEND);

    String to = emailRecipient.getText().toString();

    i.setType("message/rfc822");
    i.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
    i.putExtra(Intent.EXTRA_SUBJECT, "Pebble Accelerometer Data");
    i.putExtra(Intent.EXTRA_TEXT, "Attached are files containing accelerometer data captured by SmokeBeat Pebble app.");
    String[] dataPieces = fileManager.getListOfData(getApplicationContext());
    for(int i2 = 0; i2 < dataPieces.length; i2++){
        i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(getApplicationContext().getFilesDir() + File.separator + dataPieces[i2])));
    }
    i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(getApplicationContext().getFilesDir() + File.separator + fileManager.getCurrentFileName(getApplicationContext()))));
    Log.e("file loc", getApplicationContext().getFilesDir() + File.separator + fileManager.getCurrentFileName(getApplicationContext()));
    try {
        startActivity(Intent.createChooser(i, "Send Email"));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(Main.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
    }

datapieces 可能是空的,但是 for 循环下面的当前文件行总是可靠的,并且总是附加一些东西。

我试过改

Uri.fromFile()

Uri.parse()

当我这样做时,它会附加,但 Gmail 然后崩溃,当我检查 logcat 时,这是因为空指针。这很可能是因为 Gmail 无权访问该文件,因此结果为空。

我也试过使用

getCacheDir()

而不是

getFilesDir()

结果是一样的。

我在这里做错了什么,我应该如何解决它?一些示例代码 非常非常方便 因为我是 Android 开发的新手,并且解释我需要做什么而不需要某种推动可能不会最终有所帮助.

非常感谢。

好的伙计们。休息了一会回来,想通了。

这是它的工作原理,您需要拥有对外部存储的 write/read 权限,因此请将这些权限添加到您的清单中:

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

然后,您的文件必须从应用程序的内部存储目录复制到应用程序的外部目录。我建议您使用内部存储,这就是我在这里所做的,因此您可以自己找出 SD 卡。

这是神奇的代码块。包含日志,但您可以通过各种方式删除它们。

public void writeToExternal(Context context, String filename){
    try {
        File file = new File(context.getExternalFilesDir(null), filename); //Get file location from external source
        InputStream is = new FileInputStream(context.getFilesDir() + File.separator + filename); //get file location from internal
        OutputStream os = new FileOutputStream(file); //Open your OutputStream and pass in the file you want to write to
        byte[] toWrite = new byte[is.available()]; //Init a byte array for handing data transfer
        Log.i("Available ", is.available() + "");
        int result = is.read(toWrite); //Read the data from the byte array
        Log.i("Result", result + "");
        os.write(toWrite); //Write it to the output stream
        is.close(); //Close it
        os.close(); //Close it
        Log.i("Copying to", "" + context.getExternalFilesDir(null) + File.separator + filename);
        Log.i("Copying from", context.getFilesDir() + File.separator + filename + "");
    } catch (Exception e) {
        Toast.makeText(context, "File write failed: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); //if there's an error, make a piece of toast and serve it up
    }
}

遇到相同的附件被拒绝。清单中的权限没有任何影响,而是自API 23以来不再有任何影响。最终解决如下。

第 1 次需要在 运行 次检查并授予权限,我在主 activity:

中完成了
public static final int MY_PERMISSIONS_REQUEST_READ_STORAGE=10001;
private void checkPermission(){
    if (this.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        // Should we show an explanation?
        if (this.shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
            // Show an explanation to the user asynchronously
        } else {
            // No explanation needed, we can request the permission.
            this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_READ_STORAGE);
        }
    }
}

现在发送时,在 PUBLIC 目录中创建一个文件(尝试保存到我的应用程序文件夹 - 同样的拒绝问题)

public File createFile(){
String htmlStr="<!DOCTYPE html>\n<html>\n<body>\n<p>my html file</p></body></html>";
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "aimexplorersummary.html");
try {
      FileWriter writer = new FileWriter(file ,false);
      writer.write(htmlStr); 
      }
      writer.flush();
      writer.close();
   } catch (IOException e) {
     e.printStackTrace();
     return null;
   }
return file;
}

现在将发送意图和 putExtra 与 uri 组合到您的文件中,该文件位于 public 用户必须授予权限的存储中,现在不会造成任何问题

public void send(){
Intent intentSend = new Intent(android.content.Intent.ACTION_SEND);
intentSend.setType("text/html"); 
File file = createFile();
if(file!=null){
    intentSend.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
}
startActivity(Intent.createChooser(intentSend, "Send using:"));
}