Correo electrónico del almacenamiento interno

En mi aplicación escribo un archivo en el almacenamiento interno como cubierto en el desarrollador android . Entonces más adelante deseo enviar por correo electrónico el archivo que escribí en el almacenaje interno. Aquí está mi código y el error que estoy recibiendo, cualquier ayuda será apreciada.

FileOutputStream fos = openFileOutput(xmlFilename, MODE_PRIVATE); fos.write(xml.getBytes()); fos.close(); Intent intent = new Intent(android.content.Intent.ACTION_SEND); intent.setType("text/plain"); ... Uri uri = Uri.fromFile(new File(xmlFilename)); intent.putExtra(android.content.Intent.EXTRA_STREAM, uri); startActivity(Intent.createChooser(intent, "Send eMail..")); 

Y el error es

File: // debe señalar a file: // mnt / sdcard. Haciendo caso omiso del archivo adjunto: // …

Creo que puede haber encontrado un error (o al menos una limitación innecesaria) en el cliente android de Gmail. Pude trabajar en torno a ello, pero me parece muy específica de la aplicación, y necesitaría un poco más de trabajo para ser portátil:

First CommonsWare es muy correcto sobre la necesidad de hacer que el archivo sea legible en el mundo:

 fos = openFileOutput(xmlFilename, MODE_WORLD_READABLE); 

A continuación, debemos trabajar en torno a la insistencia de Gmail en la ruta / mnt / sdcard (o equivalente de implementación equivalente?):

 Uri uri = Uri.fromFile(new File("/mnt/sdcard/../.."+getFilesDir()+"/"+xmlFilename)); 

Al menos en mi dispositivo de Gingerbread modificado, esto es dejarme un archivo adjunto de Gmail desde el almacenamiento privado a mí mismo, y ver el contenido con el botón de vista previa cuando lo recibo. Pero no me siento muy "bueno" por tener que hacer esto para que funcione, y quién sabe qué pasaría con otra versión de Gmail u otro cliente de correo electrónico o un teléfono que monta el almacenamiento externo en otro lugar.

He estado luchando con esta edición últimamente y quisiera compartir la solución que encontré, usando FileProvider , de la biblioteca de la ayuda. Su una extensión de proveedor de contenido que resolver este problema bien sin trabajo en torno, y no es demasiado trabajo.

Como se explica en el enlace, para activar el proveedor de contenido: en tu manifiesto, escribe:

 <application .... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.youdomain.yourapp.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... 

Los metadatos deberían indicar un archivo xml en la carpeta res / xml (lo llamé file_paths.xml):

 <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path path="" name="document"/> </paths> 

La ruta de acceso está vacía cuando se utiliza la carpeta de archivos internos, pero si para una ubicación más general (ahora estamos hablando de la ruta de almacenamiento interno) debe utilizar otras rutas. El nombre que escriba se utilizará para la url que el proveedor de contenido le dará al archivo.

Y ahora, puede generar una nueva url mundialmente legible simplemente usando:

 Uri contentUri = FileProvider.getUriForFile(context, "com.yourdomain.yourapp.fileprovider", file); 

En cualquier archivo de una ruta de acceso en los metadatos res / xml / file_paths.xml.

Y ahora solo usa:

  Intent mailIntent = new Intent(Intent.ACTION_SEND); mailIntent.setType("message/rfc822"); mailIntent.putExtra(Intent.EXTRA_EMAIL, recipients); mailIntent.putExtra(Intent.EXTRA_SUBJECT, subject); mailIntent.putExtra(Intent.EXTRA_TEXT, body); mailIntent.putExtra(Intent.EXTRA_STREAM, contentUri); try { startActivity(Intent.createChooser(mailIntent, "Send email..")); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(this, R.string.Message_No_Email_Service, Toast.LENGTH_SHORT).show(); } 

No es necesario dar un permiso, lo hace automáticamente cuando se adjunta la url al archivo.

Y no necesitas hacer tu archivo MODE_WORLD_READABLE, este modo ahora está obsoleto, hazlo MODE_PRIVATE, el proveedor de contenido crea una nueva url para el mismo archivo que es accesible por otras aplicaciones.

Debo tener en cuenta que sólo lo probé en un emulador con Gmail.

Chris Stratton propuso una buena solución. Sin embargo, falla en muchos dispositivos. Usted no debe hardcode / mnt / sdcard ruta. Es mejor calcularlo:

 String sdCard = Environment.getExternalStorageDirectory().getAbsolutePath(); Uri uri = Uri.fromFile(new File(sdCard + new String(new char[sdCard.replaceAll("[^/]", "").length()]) .replace("\0", "/..") + getFilesDir() + "/" + xmlFilename)); 

Teniendo en cuenta las recomendaciones de aquí: http://developer.android.com/reference/android/content/Context.html#MODE_WORLD_READABLE , ya que la API 17 nos anima a utilizar ContentProviders, etc Gracias a ese chico y su puesto http: //stephendnicholas.com/archives/974 tenemos una solución:

 public class CachedFileProvider extends ContentProvider { public static final String AUTHORITY = "com.yourpackage.gmailattach.provider"; private UriMatcher uriMatcher; @Override public boolean onCreate() { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "*", 1); return true; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { switch (uriMatcher.match(uri)) { case 1:// If it returns 1 - then it matches the Uri defined in onCreate String fileLocation = AppCore.context().getCacheDir() + File.separator + uri.getLastPathSegment(); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); return pfd; default:// Otherwise unrecognised Uri throw new FileNotFoundException("Unsupported uri: " + uri.toString()); } } @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; } } 

Que crear archivo en caché interno:

  File tempDir = getContext().getCacheDir(); File tempFile = File.createTempFile("your_file", ".txt", tempDir); fout = new FileOutputStream(tempFile); fout.write(bytes); fout.close(); 

Intención de configuración:

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

Y registrar Proveedor de contenido en el archivo AndroidManifest:

 <provider android:name="CachedFileProvider" android:authorities="com.yourpackage.gmailattach.provider"></provider> 
 File.setReadable(true, false); 

Trabajado para mí.

El error es bastante específico: se debe utilizar el archivo de almacenamiento externo para realizar un archivo adjunto.

Si va a utilizar almacenamiento interno, intente utilizar la ruta de almacenamiento exacta:

 Uri uri = Uri.fromFile(new File(context.getFilesDir() + File.separator + xmlFilename)); 

O, además, seguir cambiando el nombre de archivo en el depurador y acaba de llamar a "nuevo archivo (bla) .exists ()" en cada uno de los archivos para ver rápidamente qué nombre exacto es su archivo

También podría ser un problema real de implementación de dispositivo específico de su dispositivo. ¿Ha intentado utilizar otros dispositivos / emulador?

  • Android Facebook SDK 4.X, cómo obtener la dirección de correo electrónico y la clave de acceso de Facebook para pasarla al servicio Web
  • Teclado amigable de correo electrónico de Android en el campo de entrada de webview
  • Android - ¿Cómo abrir la aplicación de correo electrónico?
  • Establecer dirección de correo destino en Firebase Invites
  • Cómo obtener la información de la cuenta de correo electrónico predeterminada en android ..?
  • Cómo enviar correo de forma programática en android utilizando token OAuth2.0
  • No puedo enviar correo desde Google Glass
  • Error de E / S al usar correo, activación y archivos jar adicionales en android stdio
  • Pregunta la ayuda sobre el problema de lectura de AndroidManifest.xml
  • ¿Cómo puedo enviar mensajes de correo electrónico desde mi aplicación de Android?
  • Enviar correo electrónico en Android sin usuario interacton
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.