Android - не удается подключить файл по электронной почте
По умолчанию файлы, сохраненные во внутреннем хранилище, являются приватными для вашего приложения, а другие приложения не могут получить к ним доступ (а также не могут).
Я могу видеть файл "/data/data/package_name/files/in file explite в DDMS, но когда я подключил указанный выше URI файла с помощью imageUri по электронной почте, я увидел, что прикрепленный файл имеет значение 0kb.
Я использовал API электронной почты по умолчанию для Android.
Может ли кто-нибудь предложить мне, как прикрепить файл к электронной почте, который является приватным для приложения?
хотя я успешно сохраняю файл на SD-карте и прикрепляю файл с SD-карты, это нормально работает.
Но если SD-карта недоступна и сохранение файла во внутреннем хранилище, то как я могу прикрепить их по электронной почте.
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
Когда вы пытаетесь подключить файл из внутреннего хранилища, 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
Ответ 2
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
Ответ 3
Для совместного использования частного файла вам необходимо использовать ContentProvider для обеспечения доступа к вашему файлу другими приложениями. Вот отличный пример: Android: привязка файлов из внутреннего кеша к Gmail.
Кроме того, хотя в учебнике упоминается, что вам нужно объявить своего провайдера в файле манифеста Android, он не указывает, что он должен содержаться в <application>
, поэтому убедитесь, что при объявлении он находится в пределах <application> </application>
.
Ответ 4
Этот код может помочь вам узнать о приложении:
@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>
Ответ 5
Попробуйте использовать Context.MODE_WORLD_READABLE вместо Context.MODE_PRIVATE при сохранении файла. Тогда другие приложения будут иметь доступ к файлу.
Ответ 6
Я также столкнулся с этой проблемой, используя внутренние файлы, и хотя я использовал openFileInput с MODE_WORLD_READABLE на /data/data//files/testFileName.txt и использовал 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"));
Ответ 7
Я столкнулся с той же проблемой, и после этого работал на меня.
Сначала отправьте Broadcast, чтобы уведомить устройство о том, что файл создан/установлен.
Например:
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)
{
}