【问题标题】:"Permission denied for the attachment" (on Gmail 5.0) trying to attach file to email intent“附件的权限被拒绝”(在 Gmail 5.0 上)试图将文件附加到电子邮件意图
【发布时间】:2015-01-15 04:08:56
【问题描述】:

这个问题之前已经发布过,但没有明确或可接受的答案,并且提供的所有应该“有效”的解决方案都不适合我。见这里: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();
    }

数据片段可能是空的,但是 for 循环下方的当前文件行始终是可靠的并且总是附加一些东西。

我尝试过改变

Uri.fromFile()

Uri.parse()

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

我也试过

getCacheDir()

而不是

getFilesDir()

它具有相同的结果。

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

非常感谢。

【问题讨论】:

    标签: android android-intent permissions gmail


    【解决方案1】:

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

    这是它的工作原理,您需要对外部存储具有写入/读取权限,因此将这些权限添加到您的清单中:

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

    【讨论】:

    • 问题和解决方案之间存在巨大差异 - 问题是关于共享应用程序的私有文件(来自 context.getFiles()),而答案来自一般存储(~context .getExternalFilesDir())...不是一回事...
    • 对于可能没有安装外部存储的设备,是否有一个好的通用解决方案?或者这种情况现在是否值得关注?
    • 自 Android API 23 及其新的权限系统以来,使用外部存储来存储附件已成为一种不好的做法。如果您在运行时不向用户请求 WRITE_EXTERNAL_STORAGE 权限,那么它将失败。
    【解决方案2】:

    遇到相同的附件被拒绝。清单中的权限没有任何效果,而是从API 23开始不再有效果。最终解决如下。

    第一个需要在运行时检查和授予权限,我在我的主要活动中做到了:

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

    【讨论】:

      猜你喜欢
      • 2022-01-02
      • 2015-01-09
      • 2021-06-27
      • 1970-01-01
      • 2017-04-11
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 2016-09-28
      相关资源
      最近更新 更多