studio startactivity putextra intent desde boton activity abrir android android-intent

android - startactivity - La aplicación Gmail 5.0 falla con "Permiso denegado para el archivo adjunto" cuando recibe el intento de ACTION_SEND



putextra android (8)

Utilice getExternalCacheDir() con File.createTempFile .

Use lo siguiente para crear un archivo temporal en el directorio de caché externo:

String fileName = "my_temp_file"; String fileExtension = ".tmp"; File temporaryFile = File.createTempFile( fileName, fileExtension, context.getExternalCacheDir() );

Mi aplicación crea correos electrónicos con archivos adjuntos y utiliza una intención con Intent.ACTION_SEND para iniciar una aplicación de correo.

Funciona con todas las aplicaciones de correo electrónico con las que probé, a excepción del nuevo Gmail 5.0 (funciona con Gmail 4.9), donde el correo se abre sin datos adjuntos y muestra el error: "Permiso denegado para el archivo adjunto".

No hay mensajes útiles de Gmail en Logcat. Solo probé Gmail 5.0 en Android KitKat, pero en múltiples dispositivos.

Creo el archivo para el archivo adjunto de esta manera:

String fileName = "file-name_something_like_this"; FileOutputStream output = context.openFileOutput( fileName, Context.MODE_WORLD_READABLE); // Write data to output... output.close(); File fileToSend = new File(context.getFilesDir(), fileName);

Soy consciente de las preocupaciones de seguridad con MODE_WORLD_READABLE .

Envío la intención de esta manera:

public static void compose( Context context, String address, String subject, String body, File attachment) { Intent emailIntent = new Intent(Intent.ACTION_SEND); emailIntent.setType("message/rfc822"); emailIntent.putExtra( Intent.EXTRA_EMAIL, new String[] { address }); emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject); emailIntent.putExtra(Intent.EXTRA_TEXT, body); emailIntent.putExtra( Intent.EXTRA_STREAM, Uri.fromFile(attachment)); Intent chooser = Intent.createChooser( emailIntent, context.getString(R.string.send_mail_chooser)); context.startActivity(chooser); }

¿Hay algo que hago mal al crear el archivo o enviar el intento? ¿Hay una mejor manera de iniciar una aplicación de correo con archivo adjunto? De forma alternativa, ¿alguien ha encontrado este problema y ha encontrado una solución alternativa?

¡Gracias!


Debe implementar un FileProvider , que puede crear Uris para los archivos internos de su aplicación. A otras aplicaciones se les otorga permiso para leer estos Uris. Entonces, simplemente en lugar de llamar a Uri.fromFile (archivo adjunto), crea una instancia de FileProvider y usa:

fileProvider.getUriForFile(attachment);


Estaba teniendo este problema y finalmente encontré una manera fácil de enviar correos electrónicos con archivos adjuntos. Aquí está el código

public void SendEmail(){ try { //saving image String randomNameOfPic = Calendar.DAY_OF_YEAR+DateFormat.getTimeInstance().toString(); File file = new File(ActivityRecharge.this.getCacheDir(), "slip"+ randomNameOfPic+ ".jpg"); FileOutputStream fOut = new FileOutputStream(file); myPic.compress(Bitmap.CompressFormat.JPEG, 100, fOut); fOut.flush(); fOut.close(); file.setReadable(true, false); //sending email Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"[email protected]"}); intent.putExtra(Intent.EXTRA_SUBJECT, "Recharge Account"); intent.putExtra(Intent.EXTRA_TEXT, "body text"); //Uri uri = Uri.parse("file://" + fileAbsolutePath); intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivityForResult(Intent.createChooser(intent, "Send email..."),12); }catch (Exception e){ Toast.makeText(ActivityRecharge.this,"Unable to open Email intent",Toast.LENGTH_LONG).show(); } }

En este código, "myPic" es un mapa de bits que fue devuelto por la intención de la cámara


GMail 5.0 agregó algunas verificaciones de seguridad a los archivos adjuntos que recibe de un Intento. Estos no están relacionados con los permisos de Unix, por lo que no importa el hecho de que el archivo sea legible.

Cuando Uri del archivo adjunto es un archivo: //, solo aceptará archivos del almacenamiento externo, el directorio privado de gmail o archivos legibles por todo el mundo desde el directorio de datos privados de la aplicación que realiza la llamada.

El problema con esta comprobación de seguridad es que confía en que gmail pueda encontrar la aplicación de la persona que llama, que solo es confiable cuando la persona que llama ha pedido el resultado. En su código anterior, no solicita el resultado y, por lo tanto, gmail no sabe quién llama y rechaza su archivo.

Como funcionó para usted en 4.9 pero no en 5.0, usted sabe que no es un problema de permiso de Unix, por lo que la razón debe ser las nuevas verificaciones.

Respuesta de TL; DR: reemplace startActivity con startActivityForResult.

O mejor aún, usa un proveedor de contenido.


Google tiene una answer para ese problema:

  • Almacene los datos en su propio ContentProvider , asegurándose de que otras aplicaciones tengan el permiso correcto para acceder a su proveedor. El mecanismo preferido para proporcionar acceso es usar permisos por URI que son temporales y solo otorgan acceso a la aplicación receptora. Una forma sencilla de crear un ContentProvider como este es utilizar la clase de ayuda FileProvider .

  • Use el sistema MediaStore . MediaStore está principalmente enfocado a los tipos MIME de video, audio e imagen; sin embargo, comenzando con Android 3.0 (API nivel 11) también puede almacenar tipos que no sean de medios (consulte MediaStore.Files para obtener más información). Los archivos se pueden insertar en MediaStore usando scanFile() después de lo cual un estilo de content:// Uri adecuado para compartir se pasa a la devolución de llamada onScanCompleted() proporcionada. Tenga en cuenta que una vez agregado al sistema MediaStore el contenido es accesible para cualquier aplicación en el dispositivo.

También puedes probar establecer permisos para tu archivo:

emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Y finalmente puede copiar / almacenar sus archivos en el almacenamiento externo, permisos que no son necesarios allí.


Lo probé y descubrí que definitivamente era un problema de acceso al almacenamiento privado. Cuando adjuntas un archivo a Gmail (más de 5.0) no utilices el archivo de almacenamiento privado como / data / data / package /. Intenta usar / storage / sdcard.

Puede adjuntar exitosamente su archivo.


No estoy seguro de por qué a GMail 5.0 no le gustan ciertas rutas de archivos (a las que he confirmado que tiene acceso de lectura), pero una solución aparentemente mejor es implementar su propia clase ContentProvider para servir el archivo. En realidad es algo simple, y encontré un buen ejemplo aquí: http://stephendnicholas.com/archives/974

Asegúrese de agregar la etiqueta al manifiesto de su aplicación, e incluya un "android: grantUriPermissions =" ​​true "" dentro de eso. También querrás implementar getType () y devolver el tipo MIME apropiado para el URI del archivo, de lo contrario algunas aplicaciones no funcionarán con esto ... Hay un ejemplo de eso en la sección de comentarios en el enlace.


Pude pasar un archivo .jpeg de captura de pantalla de mi aplicación a GMail 5.0 a través de un Intento. La clave estaba en esta respuesta .

Todo lo que tengo del código de @natasky es casi idéntico, pero en su lugar, tengo el directorio del archivo como

context.getExternalCacheDir();

Que "representa el directorio de almacenamiento externo donde debe guardar los archivos de caché" (documentación)