2015-01-15 2 views
8

Diese Frage wurde bereits zuvor gestellt, aber es gab keine klare oder akzeptierte Antwort und alle bereitgestellten Lösungen, die "funktionieren" sollten nicht für mich. Siehe hier: Gmail 5.0 app fails with "Permission denied for the attachment" when it receives ACTION_SEND intent"Zugriff verweigert für Anhang" (auf Google Mail 5.0) versucht, Datei an E-Mail-Absicht anzufügen

Ich habe eine App, die Daten in einer Textdatei aufbaut und die Textdatei in einer E-Mail senden muss, um sie automatisch anzuhängen. Ich habe viele Möglichkeiten ausprobiert, dies zu erreichen, und es funktioniert anscheinend für Gmail 4.9 und niedriger, aber 5.0 hat einige neue Berechtigungsfunktionen, die es davon abhalten, das zu tun, was ich mir wünsche.

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

Die datapieces könnte leer ja sein, aber die aktuelle Datei Zeile unterhalb der for-Schleife ist immer zuverlässig und legt immer etwas.

Ich habe versucht,

Uri.fromFile() 

zu

Uri.parse() 

ändern, wenn ich das tue, es legt, aber Gmail dann abstürzt und wenn ich die logcat überprüfen ist es wegen eines Null-Zeiger. Dies liegt wahrscheinlich daran, dass Google Mail keinen Zugriff auf die Datei hat und daher als null gilt.

Ich habe auch

getCacheDir() 

statt

getFilesDir() 

mit versucht, und es hat das gleiche Ergebnis.

Was mache ich hier falsch, und wie soll ich es beheben? Ein Beispielcode wäre wirklich, wirklich handlich, weil ich neu in Android Entwicklung bin und erklären, was ich ohne irgendeine Art von Abdrücken tun muss, wird wahrscheinlich nicht am Ende helfen.

Vielen Dank.

Antwort

6

In Ordnung Jungs. Nahm eine Pause und kam zurück, fand es heraus.

Hier ist, wie es funktioniert, Sie Schreib-/Leseberechtigungen für externe Speicher haben müssen, so diese Berechtigungen zu Ihrem Manifest hinzufügen:

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

Dann hat Ihre Datei von Ihrer App internen Speicherverzeichnis kopiert werden in das externe Verzeichnis der App. Ich empfehle Ihnen, internen Speicher zu verwenden, und das ist, was ich hier mache, damit Sie SD-Karten selbst herausfinden können.

Hier ist der Code-Block, der die Magie macht. Protokolle sind enthalten, aber Sie können sie auf alle Fälle entfernen.

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

Es gibt einen großen Unterschied zwischen der Frage und der Lösung - die Frage war, die privaten Dateien der Anwendung (aus context.getFiles()) zu teilen, und in der Antwort wurde es aus dem allgemeinen Speicher (~ context.getExternalFilesDir()) ... nicht das gleiche ... – Felix

+0

Gibt es eine gute allgemeine Lösung für Geräte, auf denen möglicherweise kein externer Speicher installiert ist? Oder ist dieses Szenario jetzt sogar ein Problem? – dylansturg

+0

Das Verwenden von externem Speicher zum Speichern des Anhangs ist seit Android API 23 und seinem neuen Berechtigungssystem zu einer schlechten Übung geworden. Wenn Sie den Benutzer zur Laufzeit nicht nach der Berechtigung WRITE_EXTERNAL_STORAGE fragen, schlägt er fehl. –

1

Wurde der gleiche Anhang verweigert. Berechtigungen im Manifest hatten keine Wirkung, haben aber seit API 23 keinen Effekt mehr. Zuletzt löste sie es wie folgt.

1. Notwendigkeit zu überprüfen und Erteilung von Berechtigungen für die Laufzeit, ich habe es in meiner Haupttätigkeit:

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

beim Senden einer Datei im öffentlichen Verzeichnis erstellen (versuchte meine App-Ordner Speichern - same Denial-Problem)

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

jetzt komponieren Absicht und putExtra Senden mit uri auf Ihre Datei, die in der öffentlichen Lagerhaltung ist die Benutzerberechtigungen erteilen muss und verursacht kein Problem jetzt

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