Android DownloadManager API – abrir el archivo después de descargar?

Estoy enfrentando el problema de abrir el archivo descargado después de la descarga con éxito a través de la API de DownloadManager. En mi código:

Uri uri=Uri.parse("http://www.nasa.gov/images/content/206402main_jsc2007e113280_hires.jpg"); Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .mkdirs(); lastDownload = mgr.enqueue(new DownloadManager.Request(uri) .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE) .setAllowedOverRoaming(false) .setTitle("app update") .setDescription("New version 1.1") .setShowRunningNotification(true) .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "a.apk")); Cursor c=mgr.query(new DownloadManager.Query().setFilterById(lastDownload)); if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))==8){ try { mgr.openDownloadedFile(c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID))); } catch (NumberFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.d("MGR", "Error"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.d("MGR", "Error"); } } 

El problema es cuando es if (c.getInt (c.getColumnIndex (DownloadManager.COLUMN_STATUS)) == 8) evocado. Tengo el estado -1 y la excepción. ¿Hay alguna manera mejor, cómo abrir archivos descargados con la API de DownloadManager? En mi ejemplo estoy descargando gran imagen, en situación real estaría descargando archivo APK y necesito mostrar el diálogo isntallation inmediatamente después de udpate.

Edit: Me di cuenta que el estado = 8 es después de la descarga de éxito. Es posible que tenga un enfoque diferente de "comprobación de descarga exitosa"

Gracias

Necesitas registrar un destinatario cuando la descarga esté completa:

 registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); 

Y un controlador de BroadcastReciever

 BroadcastReceiver onComplete=new BroadcastReceiver() { public void onReceive(Context ctxt, Intent intent) { // Do Something } }; 

Compra en lugar de mí rasgando todo, te sugiero que revise esto .

EDITAR:

Como sugerencia, no recomendaría usar API 9 todavía: http://developer.android.com/resources/dashboard/platform-versions.html

Hay maneras alrededor de esto, creando tu propio handler de la transferencia directa, como hice, porque no quisimos alienar la mayor parte de nuestra base del usuario del androide, para eso necesitarás: Crear AsyncTask que maneja la transferencia directa del archivo.

Y voy a recomendar para crear un diálogo de descarga de algún tipo (si usted dice que es un archivo grande, lo haría aparecer en el área de notificación).

Y que 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); } 

Problema

Android DownloadManager API – abrir el archivo después de descargar?

Solución

 /** * Used to download the file from url. * <p/> * 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. * <p/> * 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. * <p/> * 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(); } } } 

Initialize FileProvider Detalles

Decleare FileProvider en AndroidManifest

 <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.freshdesk.helpdesk.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_path"/> </provider> 

Agregue el siguiente archivo "res -> xml -> file_path.xml"

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

Nota

¿Por qué utilizar FileProvider?

  1. Desde Android 7.0 no podemos compartir FileUri con otras aplicaciones.
  2. Usando "DownloadManager.COLUMN_LOCAL_URI" obtendremos solamente FileUri por lo tanto necesitamos convertirlo en ContentUri y compartirlo con otra aplicación.

Provblem con el uso de "DownloadManager.getUriForDownloadedFile (ID largo)"

  1. No utilice "DownloadManager.getUriForDownloadedFile (long id)" – Para obtener Uri de downloadId para abrir el archivo mediante una aplicación externa.
  2. Porque de Android 6.0 y 7.0 "getUriForDownloadedFile" método devuelve uri local (que sólo puede ser accedido por nuestra aplicación), no podemos compartir ese Uri con otra aplicación, ya que no pueden acceder a ese uri (Pero está arreglado en Android 7.1 Vea Android Commit aquí ).
  3. Refere código fuente de Android DownloadManager.java & Downloads.java
  4. Por lo tanto siempre utilice la columna "DownloadManager.COLUMN_LOCAL_URI" para obtener Uri.

Referencia

  1. https://developer.android.com/reference/android/app/DownloadManager.html
  2. https://developer.android.com/reference/android/support/v4/content/FileProvider.html
  • DownloadManager doble descarga
  • DownloadManager envía STATUS_SUCCESSFUL para una descarga fallida
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.