Compartir fotos con Android con FileProvider
He leído toda la respuesta sobre este argumento pero siempre recibo un error de la aplicación que recibe mi foto.
La única manera que funcionó para mí, para toda la aplicación , fue esto (funciona porque los archivos de tarjetas SD son públicos para todas las aplicaciones ):
final File tmpFile = new File(context.getExternalCacheDir(), "exported.jpg"); Uri tmpFileUri = Uri.fromFile(tmpFile); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setDataAndType(tmpFileUri, "image/jpeg"); shareIntent.putExtra(Intent.EXTRA_STREAM, tmpFileUri); context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_image)));
Ahora, estoy atascado en cómo compartir un archivo que se encuentra en una carpeta privada. He utilizado el código proporcionado por la documentación de google:
- ¿Cómo interpreta Android la palabra clave @null en los diseños?
- Precargar la vista Web en la actividad A y pasarla a la actividad B para una carga más rápida
- StateListDrawable para cambiar filtros de color
- Proyecto Eclipse en mercurial
- ¿Esto causará fugas de memoria?
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.test.myapp.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> ... ... <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="internal_files" path="/"/> <cache-path name="internal_cache" path="/" /> </paths>
Éste es el código para compartir archivos utilizando FileProvider
pero no funciona con ninguna aplicación, excepto lo que pasa:
final File tmpFile = new File(context.getCacheDir(), "exported.jpg"); Uri tmpFileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", tmpFile); //Remove the uri permission because we overwrite the file context.revokeUriPermission(tmpFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); saveBitmapToPath(bitmap, tmpFile); bitmap.recycle(); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setDataAndType(tmpFileUri, "image/jpeg"); shareIntent.putExtra(Intent.EXTRA_STREAM, tmpFileUri); //Grant again the permissions shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_image)));
¿Por qué sigo recibiendo errores en otras aplicaciones, como esto:
java.lang.SecurityException: Permission Denial: content://com.test.myapp.fileprovider/internal_cache/exported.jpg (pid=675, uid=10052) requires null
O
IllegalArgumentException: Failed to find configuration root that contains content://com.test.myapp.fileprovider/internal_cache/exported.jpg
- Firebase android proxy setting
- Cómo reordenar los datos de la base de datos en tiempo real firebase
- autoclose DatePickerDialog
- Com.android.camera.action.CROP establece fondo de pantalla en Motorola Defy
- Cómo recuperar el valor de un atributo que contiene dos puntos en el nombre del atributo utilizando xpath
- ¿Es posible crear imágenes de forma programática en Java, Android?
- ¿Cómo obtener valores de Internet y una matriz String y pasarla a una vista de cuadrícula en Android?
- Cómo conectarse al servidor MySQL remoto a través de JDBC desde Android Applicaton
Finalmente, mirando el código fuente de la aplicación receptora, tengo la solución.
Este es el código de trabajo completo que comparto.
Espero ayudar a alguien:
<!-- AndroidManifest.xml --> <provider android:name="com.test.myapp.fileprovider.FileProvider" android:authorities="com.test.myapp.fileprovider" android:exported="true" tools:ignore="ExportedContentProvider" />
//EntryPoint private void mySharer() { ArrayList<Uri> streamUris = new ArrayList<Uri>(); for (int i = 0; i < 10; i++) { File tmpFile = new File(getContext().getCacheDir(), "tmp" + i + ".jpg"); Uri tmp = FileProvider.getUriForFile("com.test.myapp.fileprovider", tmpFile); streamUris.add(tmp); } } //Share Intent creator public final void shareUris(ArrayList<Uri> streamUris) { if (!streamUris.isEmpty()) { Intent shareIntent = new Intent(); shareIntent.putExtra(ShareCompat.EXTRA_CALLING_PACKAGE, getPackageName()); shareIntent.putExtra(ShareCompat.EXTRA_CALLING_ACTIVITY, getComponentName()); shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setType("image/jpeg"); if (streamUris.size() == 1) { shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, streamUris.get(0)); } else { shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE); shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, streamUris); } //For multiple images copy all images in the baseDir and use startActivityForResult startActivityForResult(Intent.createChooser(shareIntent, getString(R.string.share_image)), 500); } } //onResult you can delete all temp images/files with specified extensions protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 500: getContentResolver().delete(FileProvider.getUriForFile(getPackageName() + ".fileprovider", null), FileProvider.WHERE_EXTENSION, new String[]{"jpg"}); break; default: break; } } /** * This class extends the ContentProvider */ abstract class AbstractFileProvider extends ContentProvider { private final static String OPENABLE_PROJECTION_DATA = "_data"; private final static String[] OPENABLE_PROJECTION = { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, OPENABLE_PROJECTION_DATA }; @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (projection == null) { projection = OPENABLE_PROJECTION; } final MatrixCursor cursor = new MatrixCursor(projection, 1); MatrixCursor.RowBuilder b = cursor.newRow(); for (String col : projection) { if (OpenableColumns.DISPLAY_NAME.equals(col)) { b.add(getFileName(uri)); } else if (OpenableColumns.SIZE.equals(col)) { b.add(getDataLength(uri)); } else if (OPENABLE_PROJECTION_DATA.equals(col)) { b.add(getFileName(uri)); } else { b.add(null); } } return cursor; } @Override public String getType(Uri uri) { return URLConnection.guessContentTypeFromName(uri.toString()); } protected String getFileName(Uri uri) { return uri.getLastPathSegment(); } protected long getDataLength(Uri uri) { return AssetFileDescriptor.UNKNOWN_LENGTH; } @Override public Uri insert(Uri uri, ContentValues initialValues) { throw new RuntimeException("Operation not supported"); } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { throw new RuntimeException("Operation not supported"); } @Override public int delete(Uri uri, String where, String[] whereArgs) { throw new RuntimeException("Operation not supported"); } } /** * This class extends the AbstractFileProvider */ public class FileProvider extends AbstractFileProvider { public static final String CONTENT_URI = "content://"; private File baseDir; @Override public boolean onCreate() { baseDir = getContext().getCacheDir(); if (baseDir != null && baseDir.exists()) { return true; } Log.e("FileProvider", "Can't access cache directory"); return false; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File f = new File(baseDir, uri.getPath()); if (f.exists()) { return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); } throw new FileNotFoundException(uri.getPath()); } @Override protected long getDataLength(Uri uri) { File f = new File(baseDir, uri.getPath()); return f.length(); } public static Uri getUriForFile(String authority, File file) { return Uri.parse(CONTENT_URI + authority + "/" + file.getName()); } }
————- EDIT: 05/11/16 ————–
Añadido soporte para múltiples imágenes:
- Copiar todas las imágenes en la carpeta
baseDir
- Implementar el método
delete()
en elFileProvider
- Utilizar
startActivityForResult
- Escucha
onActivityResult
- Ahora puede borrar todas las imágenes temporales
Para el archivo adjunto de correo electrónico, debe esperar a que se envíe el correo electrónico antes de eliminar el archivo; de lo contrario, enviará un archivo adjunto vacío
- Robolectric y Android Studio 1.1.0 y pruebas de biblioteca
- Android – capaz de utilizar AppCompatActivity sin la biblioteca de soporte