"附件被拒绝" (在Gmail 5.0上)尝试将文件附加到电子邮件意图

时间:2015-01-15 04:08:56

标签: android android-intent permissions gmail

此问题之前已经发布过,但没有明确或接受的答案,所提供的所有“工作”的解决方案都不适合我。见这里: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开发并解释我需要做什么而不需要某种推迟可能不会最终帮助。

非常感谢。

2 个答案:

答案 0 :(得分:7)

好吧,伙计们。想休息一下然后回来,想通了。

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

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

答案 1 :(得分:1)

遇到相同的附件被拒绝。清单中的权限没有任何影响,而是自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目录中创建一个文件(尝试保存到我的app文件夹 - 同样的拒绝问题)

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