Прикрепление файла из внутреннего хранилища к электронной почте

#android #file #email #android-intent #internal

#Android #файл #Адрес электронной почты #android-намерение #внутренний

Вопрос:

В подобных темах здесь нет ответов, которые помогли… Я хочу создать сообщение электронной почты с вложенным файлом, файл находится во внутреннем хранилище. Вот код:

 Intent i = new Intent(Intent.ACTION_SEND);
    i.setType("text/plain");
    i.putExtra(Intent.EXTRA_EMAIL  , new String[]{email});
    i.putExtra(Intent.EXTRA_SUBJECT, "Smart Weight Tracker");
    i.putExtra(Intent.EXTRA_TEXT   , "CSV file is in attachment");

    Uri uri;
    if(useExternal){
        uri = Uri.fromFile(new File(this.getExternalFilesDir(null),fname));
    }
    else{
        File f = new File(this.getFilesDir(),fname);
        f.setReadable(true, false);
        f.setWritable(true, false);
        uri = Uri.fromFile(f);
    }

    i.putExtra(Intent.EXTRA_STREAM, uri);

    try {
        startActivity(Intent.createChooser(i, "Send mail..."));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(MainActivity.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
    }
 

Он отлично работает с внешним хранилищем, но у меня нет прикрепления при использовании внутреннего хранилища.
Я проверил — файл открывается (его длина в моем приложении отображается с помощью тоста — нормально,> 0).

Я пишу это так:

   OutputStreamWriter out =
                new OutputStreamWriter(con.openFileOutput(fname, Context.MODE_WORLD_READABLE));
 

В logcat я вижу

 I/Gmail   (28480): >>>>> Attachment uri: file:///data/data/Android.MyApp/files     /31.10.2011.csv
I/Gmail   (28480): >>>>>           type: text/plain
I/Gmail   (28480): >>>>>           name: 31.10.2011.csv
I/Gmail   (28480): >>>>>           size: 0

Size == 0!
 

Есть идеи?

Ответ №1:

Привет, попробуйте использовать контент-провайдеров.

 emailIntent.putExtra(Intent.EXTRA_STREAM,Uri.parse("content://"   CachedFileProvider.AUTHORITY   "/"  fileName)); 
 

……..
Android: прикрепление файлов из внутреннего кэша к 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 amp; 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.gmailattach.provider">

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

http://stephendnicholas.com/archives/974#comment-342

Комментарии:

1. OP не запрашивал конкретное решение для GMail.

2. Кто-нибудь еще смотрит на это семь лет спустя - это все еще работает, и это не обязательно должно быть специфичным для Gmail, если вы исключаете класс из намерения (на самом деле, вы должны - я предполагаю, что они что-то изменили в этом имени класса; не будет работать, если оно установлено). Кроме того, убедитесь, что вы установили флаг намерения с помощью emailIntent.addFlags(Намерение. FLAG_GRANT_READ_URI_PERMISSION) и убедитесь, что у вашего <провайдера> есть android: grantUriPermissions="true", иначе ничего не произойдет.

Ответ №2:

 Uri fileUri = Uri.fromFile(new File(context.getCacheDir()  "/"  fileName));                                           

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
                    "Test Subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
                    "go on read the emails");
emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);

startActivity(emailIntent);
 

Пожалуйста, попробуйте этот код. Надеюсь, это поможет.

Комментарии:

1. Спасибо ... но результат тот же. Размер 0 в logcat, нет файла во вложении

Ответ №3:

Я часами следил за кодом stephendnicholas, думая, что мне НУЖНО записать свои файлы во внутреннее хранилище, потому что на моем устройстве не было SD-карты.

Создание моего "внутреннего" файла, подобного этому, отлично сработало для меня:

 File file = new File(getExternalFilesDir(null), filename); // :)
 

Это позволило избежать ограничений Gmail во время вложения.

До этого я создавал свой файловый объект следующим образом:

 File file = new File(this.getFilesDir(), filename); //will not attach
 

Но если ваш файл буквально из внутреннего хранилища, тогда контент-провайдеры stephendnicholas и т. Д. работайте, если у вас есть безумные навыки работы с Android.