Recuperar la ruta de acceso del archivo de la intención de DownloadManager detectada

Desde Android 4.2 si un usuario descarga algún archivo en el navegador se utiliza el DownloadManager. Si el usuario hace clic en la notificación de "descarga completa", un intento es y siempre se inició. Antes de Android 4.2, la intención era tener la ruta del archivo descargado en el contenido, de modo que:

intent.getData() 

file:///storage/emulated/0/Download/some_file.ext una cadena como file:///storage/emulated/0/Download/some_file.ext . Sin embargo, desde Android 4.2 el gestor de descargas difunde e intenta con un esquema de content , como el content://downloads/all_downloads/2334 .

¿Cómo recupero la ruta del archivo local para un archivo descargado?

He intentado lo siguiente:

 public static String getRealPathFromURI(Uri contentUri, Activity activity) { DownloadManager downloadManager = (DownloadManager) activity.getSystemService(Activity.DOWNLOAD_SERVICE); String[] contentParts = contentUri.getEncodedPath().split("/"); Cursor q = downloadManager.query(new DownloadManager.Query().setFilterById(Integer.parseInt(contentParts[contentParts.length - 1]))); if (q == null) { // Download no longer exists return null; } q.moveToFirst(); return q.getString(q.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME)); } 

Pero el cursor nunca devuelve ninguna fila (por lo que q.getCount() == 0 y por lo tanto la última declaración return una excepción). Además, el hack al analizar la identificación del archivo de descarga desde el Uri parece extraño.

ACTUALIZACIÓN: También he intentado:

 input = getActivity().getContentResolver().openInputStream(contentUri); 

Pero esto devuelve un error que indica

Permiso Negación: lectura com.android.providers.downloads.DownloadProvider uri contenido: // downloads / all_downloads / 2334 desde pid = 30950, uid = 10064 requiere android.permission.ACCESS_ALL_DOWNLOADS, o grantUriPermission ()

Es evidente que no puedo acceder a las descargas (ya que mi aplicación no las inició – el navegador sí) a través de ContentProvider .

Obtener a través de la resolución de contenido es lo correcto. No cada URL de contenido va a ser un archivo. Por ejemplo, la aplicación Galería le proporcionará uri que traducir a una llamada de red o un archivo local dependiendo de la fuente.

Incluso si llegas a la ruta del archivo real, es probable que no pueda leerlo, debido a los permisos de archivo, aunque puede tener suerte de que está en el almacenamiento externo. ¿Has probado a agregar android.permission.ACCESS_ALL_DOWNLOADS a tu aplicación como sugiere la excepción? Eso no funcionará, ya que el permiso es a nivel de firma 🙁

Esto es lo que funcionó. En primer lugar, no puede (y no debe querer) obtener la ruta del archivo como botteaap correctamente señalado. (Créditos a él por establecerme en el camino correcto.) En su lugar obtendrá un permiso temporal automáticamente para acceder al contenido del archivo, usando:

 InputStream input = getContentResolver().openInputStream(intent.getData()); 

Puede leer este InputStream como cualquier otro en Java. Parece que no hay manera de obtener el nombre del archivo. Si necesita un archivo, primero escriba el flujo de entrada en un archivo (temporal).

La SecurityException es lanzada cuando se revocó su acceso temporal. Esto sucedió para mí en algunos archivos que traté de leer incorrectamente antes y específicamente cuando el Intención fue recogido en mi Acticity onNewIntent .

Solo quiero añadir a la respuesta de @erickok ya que me tomó varias horas entender esto. Como se indica por @ jcesarmobile, sólo se garantiza que sea capaz de obtener el nombre y el tamaño del archivo, no la ruta completa.

Puede obtener el nombre y el tamaño de la siguiente manera y, a continuación, guardar en un archivo temporal:

 String filename = null; Long filesize = null; Cursor cursor = null; try { cursor = this.getContentResolver().query(intent.getData(), new String[] { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { filename = cursor.getString(0); filesize = cursor.getLong(1); } } finally { if (cursor != null) cursor.close(); } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.