Solución:
Problema
API DownloadManager de Android: ¿abrir el archivo después de descargarlo?
Solución
/**
* Used to download the file from url.
*
* 1. Download the file using Download Manager.
*
* @param url Url.
* @param fileName File Name.
*/
public void downloadFile(final Activity activity, final String url, final String fileName)
try
if (url != null && !url.isEmpty())
Uri uri = Uri.parse(url);
activity.registerReceiver(attachmentDownloadCompleteReceive, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setMimeType(getMimeType(uri.toString()));
request.setTitle(fileName);
request.setDescription("Downloading attachment..");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
dm.enqueue(request);
catch (IllegalStateException e)
Toast.makeText(activity, "Please insert an SD card to download file", Toast.LENGTH_SHORT).show();
/**
* Used to get MimeType from url.
*
* @param url Url.
* @return Mime Type for the given url.
*/
private String getMimeType(String url)
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null)
MimeTypeMap mime = MimeTypeMap.getSingleton();
type = mime.getMimeTypeFromExtension(extension);
return type;
/**
* Attachment download complete receiver.
*
* 1. Receiver gets called once attachment download completed.
* 2. Open the downloaded file.
*/
BroadcastReceiver attachmentDownloadCompleteReceive = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action))
long downloadId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
openDownloadedAttachment(context, downloadId);
;
/**
* Used to open the downloaded attachment.
*
* @param context Content.
* @param downloadId Id of the downloaded file to open.
*/
private void openDownloadedAttachment(final Context context, final long downloadId)
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToFirst())
int downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
String downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
String downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
if ((downloadStatus == DownloadManager.STATUS_SUCCESSFUL) && downloadLocalUri != null)
openDownloadedAttachment(context, Uri.parse(downloadLocalUri), downloadMimeType);
cursor.close();
/**
* Used to open the downloaded attachment.
*
* 1. Fire intent to open download file using external application.
*
* 2. Note:
* 2.a. We can't share fileUri directly to other application (because we will get FileUriExposedException from Android7.0).
* 2.b. Hence we can only share content uri with other application.
* 2.c. We must have declared FileProvider in manifest.
* 2.c. Refer - https://developer.android.com/reference/android/support/v4/content/FileProvider.html
*
* @param context Context.
* @param attachmentUri Uri of the downloaded attachment to be opened.
* @param attachmentMimeType MimeType of the downloaded attachment.
*/
private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType)
if(attachmentUri!=null)
// Get Content Uri.
if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme()))
// FileUri - Convert it to contentUri.
File file = new File(attachmentUri.getPath());
attachmentUri = FileProvider.getUriForFile(activity, "com.freshdesk.helpdesk.provider", file);;
Intent openAttachmentIntent = new Intent(Intent.ACTION_VIEW);
openAttachmentIntent.setDataAndType(attachmentUri, attachmentMimeType);
openAttachmentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try
context.startActivity(openAttachmentIntent);
catch (ActivityNotFoundException e)
Toast.makeText(context, context.getString(R.string.unable_to_open_file), Toast.LENGTH_LONG).show();
Inicializar los detalles del proveedor de archivos
Decleare FileProvider en AndroidManifest
Agregue el siguiente archivo “res -> xml -> file_path.xml”
Nota
Por qué utilizar FileProvider
- Desde Android 7.0 no podemos compartir FileUri con otras aplicaciones.
- Usando “DownloadManager.COLUMN_LOCAL_URI” obtendremos solo FileUri, por lo tanto, necesitamos convertirlo en ContentUri y compartirlo con otra aplicación.
Problema con el uso de “DownloadManager.getUriForDownloadedFile (identificación larga)”
- No use “DownloadManager.getUriForDownloadedFile (ID largo)” – Para obtener Uri de downloadId para abrir el archivo usando una aplicación externa.
- Debido a que desde Android 6.0 y 7.0 el método “getUriForDownloadedFile” devuelve un uri local (al que solo puede acceder nuestra aplicación), no podemos compartir ese Uri con otra aplicación porque no pueden acceder a ese uri (pero está arreglado en Android 7.1 consulte Confirmación de Android aquí).
- Consulte el código fuente de Android DownloadManager.java y Downloads.java
- Por lo tanto, utilice siempre la columna “DownloadManager.COLUMN_LOCAL_URI” para obtener Uri.
Referencia
- https://developer.android.com/reference/android/app/DownloadManager.html
- https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Debe registrar un receptor para cuando se complete la descarga:
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
y un controlador BroadcastReciever
BroadcastReceiver onComplete=new BroadcastReceiver()
public void onReceive(Context ctxt, Intent intent)
// Do Something
;
Compre en lugar de que yo estampe todo, le sugiero que revise esto.
EDITAR:
Solo como sugerencia, no recomendaría usar API 9 todavía: http://developer.android.com/resources/dashboard/platform-versions.html
Hay formas de evitar esto, creando su propio controlador de descarga, como hice yo, porque no queríamos alienar a la mayor parte de la base de usuarios de Android, para eso necesitará: Create AsyncTask que maneja la descarga del archivo.
y recomendaré crear un cuadro de diálogo de descarga de algún tipo (si dices que es un archivo grande, lo haré aparecer en el área de notificación).
y luego necesitará manejar la apertura del archivo:
protected void openFile(String fileName)
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(new File(fileName)),
"MIME-TYPE");
startActivity(install);
Si crees que ha sido de provecho este post, agradeceríamos que lo compartas con el resto juniors de este modo nos ayudas a dar difusión a nuestro contenido.