2010-11-08 13 views
11

Per impostazione predefinita, i file salvati nella memoria interna sono privati ​​per l'applicazione e altre applicazioni non possono accedervi (né l'utente può).Android: impossibile allegare un file all'e-mail

Sono in grado di vedere il file "/ data/data/nome_pacchetto/file/in file esplorare in DDMS, ma quando ho collegato l'URI di file sopra usando imageUri in email, ho visto che il file allegato è di 0kb. ho usato le API di posta elettronica di default di Android.

qualcuno mi può suggerire, come allegare un file in e-mail che è privato per l'applicazione?

anche se io sono riuscito in grado di salvare il file nella scheda SD e allegando il file dalla scheda SD, funziona correttamente

Ma se la scheda SD non è disponibile e s aving il file nella memoria interna, quindi come posso allegarli in e-mail.

String FILENAME = "hello_file.txt"; 
String string = "hello world!";FileOutputStream fos = openFileOutput(FILENAME,  Context.MODE_PRIVATE); 
fos.write(string.getBytes()); 
fos.close(); 

File imageFile = getFileStreamPath(FILENAME); 
Uri imageUri = Uri.fromFile(imageFile); 

final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); 
emailIntent.setType("*/*"); 
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM,imageUri); 

this.startActivityForResult(Intent.createChooser(emailIntent, "Send mail..."),SUB_ACTIVITY); 
+1

Hai mai trovato una soluzione a questo problema? – JehandadK

+0

Ho affrontato il problema simile. Dalla scheda SD funziona perfettamente ... Ma dalla memoria interna non ho avuto successo in questa funzionalità. Forse giocare con i tipi MIME ti aiuterà ad andare avanti .. – Mike

+0

potresti per favore elobrarlo? – pankaj

risposta

1

Prova utilizzando Context.MODE_WORLD_READABLE invece di Context.MODE_PRIVATE durante il salvataggio del file. Quindi altre app avranno accesso al file.

+0

@, avevo già provato con MODE_WORLD_WRITEABLE, ma non funziona. – pankaj

+0

@pankaj ma hai provato con MODE_WORLD_READABLE? –

6

Quando si tenta di allegare file dalla memoria interna, GMail scrive un errore nel registro:

applicazione
ERROR/Gmail(...): file:// attachment paths must point to file:///mnt/sdcard. 

E-mail indicherebbe il file allegato anche se non ha fatto fisicamente esiste.

Per quanto riguarda una memoria esterna, la documentazione dice che:

dispositivo compatibile con Android Ogni supporta un condiviso "storage esterno" che è possibile utilizzare per salvare i file. Può trattarsi di un supporto di memorizzazione rimovibile (come una scheda SD) o di una memoria interna (non rimovibile).

Ciò significa che non devi preoccuparti del fatto che il dispositivo non disponga di una memoria esterna. Tuttavia, lo storage esterno può non essere disponibile a volte. Fare riferimento a http://developer.android.com/guide/topics/data/data-storage.html#filesExternal

+0

Grazie! Non riuscivo a capire perché stava fallendo e non pensavo di cambiare i filtri sulla mia finestra LogCat. –

1

Ho anche sperimentato questo problema utilizzando i file interni e, anche se ho usato openFileInput con MODE_WORLD_READABLE sul /data/data//files/testFileName.txt e utilizzato l'URI.parse con l'extra "/" (vedi sotto), il test ricevuto via e-mail è ancora privo dell'allegato desiderato. Mi spiace ma non c'è una risposta, tranne provare a usare i file esterni sulla scheda SD - che è il mio prossimo esperimento!

Codice:

File tmpFile = new File(context.getFilesDir(), mfileName); 
     Log.d(TAG, tmpFile.toString()); 
// This shows: /data/data/org.eddiem.adeveloper.flatfiletest/files/testFile.csv 
     //File tmpFile2 = new File(context.getFileStreamPath(mfileName), mfileName); 
     //Log.v(TAG, tmpFile2.toString()); 
// This also shows: /data/data/org.eddiem.adeveloper.flatfiletest/files/testFile.csv 

     //Uri uri = Uri.fromFile(new File(context.getFileStreamPath(mfileName), mfileName)); 
     Uri uri = Uri.parse("file://" + tmpFile.toString()); 
     //Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), 
     //        mfileName)); 
     Log.d(TAG, "Uri-path is: " + uri.getPath()); // or .toString() 

     Intent i = new Intent(android.content.Intent.ACTION_SEND); 
     i.setType("text/plain"); 
     i.putExtra(Intent.EXTRA_EMAIL, new String[]{"[email protected]"}); 
     i.putExtra(Intent.EXTRA_SUBJECT, "Test Email - with Attachment"); 
     i.putExtra(Intent.EXTRA_TEXT, "This is a test Email with an Attachment."); 
     i.putExtra(Intent.EXTRA_STREAM, uri); 
     //startActivity(Intent.createChooser(i, "Select application")); 
     startActivity(Intent.createChooser(i, "Send mail")); 
4

Al fine di condividere un file privato è necessario utilizzare un ContentProvider per fornire l'accesso al file da altre applicazioni. Ecco un ottimo esempio: Android: Attaching files from internal cache to Gmail.

Inoltre, anche se il tutorial menziona che è necessario dichiarare il proprio provider nel file manifest di Android, esso non specifica che dovrebbe essere contenuto in <application>, quindi assicurarsi che quando lo si dichiari sia entro <application> </application>.

3

Questo codice può aiutarti a ottenere idea di attaccamento:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    buttonSend = (Button) findViewById(R.id.buttonSend); 

    textTo = (EditText) findViewById(R.id.editTextTo); 
    textSubject = (EditText) findViewById(R.id.editTextSubject); 
    textMessage = (EditText) findViewById(R.id.editTextMessage); 

    buttonSend.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      String to = textTo.getText().toString(); 
      String subject = textSubject.getText().toString(); 
      String message = textMessage.getText().toString(); 

      Intent i = new Intent(Intent.ACTION_SEND); 
      i.setType("plain/text"); 
      File data = null; 

      try { 
       Date dateVal = new Date(); 
       String filename = dateVal.toString(); 
       data = File.createTempFile("Report", ".csv"); 
       FileWriter out = (FileWriter) GenerateCsv.generateCsvFile(
               data, "Name,Data1"); 
       i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(data)); 
       i.putExtra(Intent.EXTRA_EMAIL, new String[] { to }); 
       i.putExtra(Intent.EXTRA_SUBJECT, subject); 
       i.putExtra(Intent.EXTRA_TEXT, message); 
       startActivity(Intent.createChooser(i, "E-mail")); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

public class GenerateCsv 
{ 
    public static FileWriter generateCsvFile(File sFileName,String fileContent) 
    { 
     FileWriter writer = null; 

     try { 
      writer = new FileWriter(sFileName); 
      writer.append(fileContent); 
      writer.flush(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       writer.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

     return writer; 
    } 
} 

Il codice di cui sopra richiede di aggiungere il seguente autorizzazione al file manifest:

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

Semplice e chiaro –

5
Android: Attaching files from internal cache to Gmail 




package com.stephendnicholas.gmailattach; 

import java.io.File; 
import java.io.FileNotFoundException; 

import android.content.ContentProvider; 
import android.content.ContentValues; 
import android.content.UriMatcher; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.ParcelFileDescriptor; 
import android.util.Log; 

public class CachedFileProvider extends ContentProvider { 

    private static final String CLASS_NAME = "CachedFileProvider"; 

    // The authority is the symbolic name for the provider class 
    public static final String AUTHORITY = "com.stephendnicholas.gmailattach.provider"; 

    // UriMatcher used to match against incoming requests 
    private UriMatcher uriMatcher; 

    @Override 
    public boolean onCreate() { 
     uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 

     // Add a URI to the matcher which will match against the form 
     // 'content://com.stephendnicholas.gmailattach.provider/*' 
     // and return 1 in the case that the incoming Uri matches this pattern 
     uriMatcher.addURI(AUTHORITY, "*", 1); 

     return true; 
    } 

    @Override 
    public ParcelFileDescriptor openFile(Uri uri, String mode) 
      throws FileNotFoundException { 

     String LOG_TAG = CLASS_NAME + " - openFile"; 

     Log.v(LOG_TAG, 
       "Called with uri: '" + uri + "'." + uri.getLastPathSegment()); 

     // Check incoming Uri against the matcher 
     switch (uriMatcher.match(uri)) { 

     // If it returns 1 - then it matches the Uri defined in onCreate 
     case 1: 

      // The desired file name is specified by the last segment of the 
      // path 
      // E.g. 
      // 'content://com.stephendnicholas.gmailattach.provider/Test.txt' 
      // Take this and build the path to the file 
      String fileLocation = getContext().getCacheDir() + File.separator 
        + uri.getLastPathSegment(); 

      // Create & return a ParcelFileDescriptor pointing to the file 
      // Note: I don't care what mode they ask for - they're only getting 
      // read only 
      ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File( 
        fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); 
      return pfd; 

      // Otherwise unrecognised Uri 
     default: 
      Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'."); 
      throw new FileNotFoundException("Unsupported uri: " 
        + uri.toString()); 
     } 
    } 

    // ////////////////////////////////////////////////////////////// 
    // Not supported/used/required for this example 
    // ////////////////////////////////////////////////////////////// 

    @Override 
    public int update(Uri uri, ContentValues contentvalues, String s, 
      String[] as) { 
     return 0; 
    } 

    @Override 
    public int delete(Uri uri, String s, String[] as) { 
     return 0; 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues contentvalues) { 
     return null; 
    } 

    @Override 
    public String getType(Uri uri) { 
     return null; 
    } 

    @Override 
    public Cursor query(Uri uri, String[] projection, String s, String[] as1, 
      String s1) { 
     return null; 
    } 
} 




<provider android:name="CachedFileProvider" android:authorities="com.stephendnicholas 





public static void createCachedFile(Context context, String fileName, 
      String content) throws IOException { 

    File cacheFile = new File(context.getCacheDir() + File.separator 
       + fileName); 
    cacheFile.createNewFile(); 

    FileOutputStream fos = new FileOutputStream(cacheFile); 
    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); 
    PrintWriter pw = new PrintWriter(osw); 

    pw.println(content); 

    pw.flush(); 
    pw.close(); 
} 




public static Intent getSendEmailIntent(Context context, String email, 
      String subject, String body, String fileName) { 

    final Intent emailIntent = new Intent( 
       android.content.Intent.ACTION_SEND); 

    //Explicitly only use Gmail to send 
    emailIntent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail"); 

    emailIntent.setType("plain/text"); 

    //Add the recipients 
    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, 
       new String[] { email }); 

    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject); 

    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body); 

    //Add the attachment by specifying a reference to our custom ContentProvider 
    //and the specific file of interest 
    emailIntent.putExtra( 
      Intent.EXTRA_STREAM, 
       Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/" 
         + fileName)); 

    return emailIntent; 
} 

    enter code here 
+0

Esattamente ciò di cui avevo bisogno, ma aggiungere la fonte sarebbe bello: http://stephendnicholas.com/archives/974. L'ho trovato utile anche perché è un po 'più strutturato. – Compufreak

0

stavo affrontando lo stesso problema e il seguito ha funzionato per me.

Prima inviare Broadcast per notificare al dispositivo che il file è stato creato/montato.

Ad esempio:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+storagePath))); 

Quindi utilizzare il codice per inviare mail con allegato.

Intent email = new Intent(Intent.ACTION_SEND); 
email.putExtra(Intent.EXTRA_EMAIL, "Receiver Email Address"); 
email.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
email.putExtra(Intent.EXTRA_SUBJECT, "Subject"); 
email.putExtra(Intent.EXTRA_TEXT,"Email Text"); 

//Mime type of the attachment (or) u can use sendIntent.setType("*/*") 
//email.setType("text/plain"); 
email.setType("application/YourMimeType"); 

//Full Path to the attachment 
email.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+storagePath)); 
try 
{ 
    startActivity(Intent.createChooser(email, "Send Message...")); 
} 
catch (android.content.ActivityNotFoundException ex) 
{ 

}