2015-01-15 9 views
8

Questa domanda è stata postata prima, ma non c'era una risposta chiara o accettata e tutte le soluzioni fornite che dovevano "funzionare" non ha fatto per me Vedi qui: Gmail 5.0 app fails with "Permission denied for the attachment" when it receives ACTION_SEND intent"Autorizzazione negata per l'allegato" (su Gmail 5.0) che tenta di allegare un file all'intenzione dell'email

Ho un'app che crea i dati in un file di testo e deve inviare il file di testo in una e-mail, allegandolo automaticamente. Ho provato molti modi per ottenere questo da allegare, e apparentemente funziona per Gmail 4.9 e versioni precedenti, ma 5.0 ha alcune nuove funzioni di autorizzazione che impediscono di fare ciò che desidero.

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

I datapieces potrebbero essere sì vuoti ma la linea di file corrente al di sotto del ciclo for è sempre affidabile e sempre attribuisce qualcosa.

Ho provato a cambiare

Uri.fromFile() 

a

Uri.parse() 

Quando lo faccio, annette, ma poi si blocca Gmail e quando si controlla il logcat è perché di un puntatore nullo. Ciò è probabilmente dovuto al fatto che Gmail non ha accesso al file e pertanto risulta nullo.

Ho anche provato con

getCacheDir() 

anziché

getFilesDir() 

ed ha lo stesso risultato.

Cosa sto facendo di sbagliato qui, e come dovrei andare a ripararlo? Qualche esempio di codice sarebbe davvero, davvero a portata di mano perché io sono nuovo nello sviluppo di Android e spiegando che cosa ho bisogno di fare senza una sorta di push off probabilmente non finirà per aiutare.

Grazie mille.

risposta

6

Ok ragazzi. Ho fatto una pausa e sono tornato, ho capito.

Ecco come funziona, è necessario disporre di permessi di scrittura/lettura per storage esterno, in modo da aggiungere queste autorizzazioni per il vostro manifesto:

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

Poi, il file deve essere copiato dalla directory di memoria interna del app nella directory esterna dell'app. Vi consiglio di utilizzare la memoria interna, ed è quello che sto facendo qui in modo da poter capire le schede SD da soli.

Ecco il blocco di codice che fa la magia. I log sono inclusi ma è possibile rimuoverli con tutti i mezzi.

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

C'è una grande differenza tra la domanda e la soluzione: la domanda riguardava la condivisione dei file privati ​​dell'app (da context.getFiles()), e nella risposta è diventata dalla memoria generale (~ context.getExternalFilesDir()) ... Non è la stessa cosa ... – Felix

+0

Esiste una buona soluzione generale per i dispositivi che potrebbero non essere montati su storage esterno? O quello scenario è anche una preoccupazione ora? – dylansturg

+0

L'utilizzo di una memoria esterna per archiviare l'allegato è diventato una cattiva pratica dall'API Android 23 e dal suo nuovo sistema di autorizzazioni. Se non chiedi all'utente l'autorizzazione WRITE_EXTERNAL_STORAGE al runtime, allora fallirà. –

1

incontrato lo stesso attaccamento negato. Le autorizzazioni in manifest non hanno avuto alcun effetto, anzi non hanno più alcun effetto dall'API 23. Finalmente risolto come segue.

prima necessità di controllare e concedere le autorizzazioni in fase di esecuzione, l'ho fatto nella mia attività principale:

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

Ora, quando l'invio, creare un file nella directory PUBLIC (tentato il salvataggio della mia cartella app - stesso problema negazione)

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

ora comporre l'invio di intenti e putExtra con URI per il file che è in deposito pubblico che l'utente deve concedere le autorizzazioni per e che causa nessun problema ora

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