2010-11-08 127 views
11

默認情況下,保存到內部存儲的文件對您的應用程序是私人的,其他應用程序無法訪問它們(用戶也無法訪問它們)。Android - 無法在電子郵件中附加文件

我能夠在DDMS中看到文件「/ data/data/package_name/files /文件瀏覽」,但是當我在電子郵件中使用imageUri連接上述文件URI時,則看到附加文件爲0kb。 我已經使用了Android的默認電子郵件的API。

任何人都可以給我建議,如何附加文件的電子郵件是私人的應用程序?

雖然我成功了能夠保存在SD卡上的文件並從SD卡附加文件,這是工作正常。

但如果SD卡不可用和s將文件存入內部存儲器,然後如何將它們附加到電子郵件中。

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

你有沒有碰到過這個問題的解決方案? – JehandadK 2011-08-16 11:29:05

+0

我面臨類似的問題。從SD卡工作得很好...但從內部存儲我沒有成功的這個功能。也許玩MIME類型將有助於繼續.. – Mike 2010-11-08 12:24:17

+0

可以請你提倡嗎? – pankaj 2010-11-09 05:52:55

回答

1

嘗試保存文件時使用Context.MODE_WORLD_READABLE代替Context.MODE_PRIVATE。然後其他應用程序將有權訪問該文件。

+0

@,我已經嘗試了MODE_WORLD_WRITEABLE,但它不起作用。 – pankaj 2010-11-08 11:48:09

+0

@ pankaj但你有沒有嘗試MODE_WORLD_READABLE? – 2010-11-08 13:45:02

6

當您嘗試從內部存儲連接文件,GMail的錯誤寫入日誌:

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

的電子郵件應用程序會告訴你附加的文件,即使它沒有實際存在。

至於外部存儲,文件說:

每一個Android兼容設備支持共享「外部存儲」,你可以用它來保存文件。這可以是可移動存儲介質(如SD卡)或內部(不可移動)存儲器。

這意味着您不必擔心設備根本沒有外部存儲。儘管如此,外部存儲器有時仍然不可用。請參閱http://developer.android.com/guide/topics/data/data-storage.html#filesExternal

+0

謝謝!我無法弄清楚它爲什麼會失敗,我不認爲要更改我的LogCat窗口上的過濾器。 – 2013-03-10 02:16:15

1

我也遇到過使用內部文件這個問題,儘管我已經/data/data//files/testFileName.txt使用openFileInput與MODE_WORLD_READABLE並使用額外的「/」的URI.parse(見以下),收到的測試通過電子郵件仍然缺乏理想的依戀。很抱歉,除了嘗試在SD卡上使用外部文件 - 這是我的下一個實驗,沒有答案!

代碼:

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

爲了分享你需要使用ContentProvider的其他應用程序提供訪問您的文件私人文件。這是一個很好的例子:Android: Attaching files from internal cache to Gmail。此外,雖然本教程提到您需要在Android清單文件中聲明您的提供程序,但它並未指定它應該包含在<application>中,因此請確保在聲明它時在<application> </application>之內。

3

本準則也許能幫助您獲得有關附件的想法:

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

上面的代碼需要您以下權限添加到您的清單文件:

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

簡單明瞭 – 2016-08-07 10:18:58

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

正是我需要的,但添加源代碼會很好:http://stephendnicholas.com/archives/974。我還發現它有點結構化。 – Compufreak 2015-01-23 11:33:10

0

我面臨同樣的問題和以下爲我工作。

首先發送廣播通知設備文件被創建/掛載。

例如:

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

然後使用代碼與附件發送郵件。

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) 
{ 

} 
相關問題