Получить путь к файлу из пойманного намерения DownloadManager

Начиная с Android 4.2, если пользователь загружает какой-либо файл в браузере, используется DownloadManager. Если пользователь нажимает на уведомление «загрузить полный», Intent всегда запускается. Перед Android 4.2 предполагалось, что для содержимого загруженного файла в нем используется намерение:

intent.getData() 

file:///storage/emulated/0/Download/some_file.ext строку, такую ​​как file:///storage/emulated/0/Download/some_file.ext . Однако, начиная с Android 4.2, диспетчер загрузки осуществляет трансляцию и намерение с помощью схемы content , например, content://downloads/all_downloads/2334 .

Как получить путь к локальному файлу для загруженного файла?

Я пробовал следующее:

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

Но курсор никогда не возвращает никаких строк (поэтому q.getCount() == 0 и поэтому последний оператор return генерирует исключение). Кроме того, взлом, анализирующий идентификатор файла загрузки из Uri, кажется странным.

ОБНОВЛЕНИЕ: Я также пробовал:

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

Но это возвращает сообщение об ошибке

Разрешение отказа: чтение com.android.providers.downloads.DownloadProvider uri content: // downloads / all_downloads / 2334 из pid = 30950, uid = 10064 требует android.permission.ACCESS_ALL_DOWNLOADS или grantUriPermission ()

Очевидно, что я не могу получить доступ к загрузкам (поскольку мое приложение не инициировало их – браузер сделал) через ContentProvider .

Пройти через контент-резольвер – это правильно. Не каждый URL-адрес контента будет файлом. Например, приложение Gallery предоставит вам uri, который переводит на сетевой вызов или локальный файл в зависимости от источника.

Даже если вы дойдете до реального пути к файлу, вы, вероятно, не сможете его прочитать, из-за прав доступа к файлам, хотя вам может быть повезло, что он находится на внешнем хранилище. Вы пробовали добавить в приложение приложение android.permission.ACCESS_ALL_DOWNLOADS , как это предлагает исключение? Это не сработает, так как разрешение находится на уровне подписи 🙁

Вот что сработало. Во-первых, вы не можете (и не должны) получить путь к файлу, как указано в botteaap. (Кредиты для него, чтобы установить меня по правильному пути.) Вместо этого вы автоматически получаете временное разрешение на доступ к содержимому файла, используя:

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

Вы можете прочитать этот InputStream как и любой другой на Java. Кажется, нет никакого способа получить имя файла. Если вам нужен файл, сначала напишите входной поток в (временный) файл.

SecurityException бросается, когда ваш временный доступ был отменен. Это случалось для меня в некоторых файлах, которые я пытался прочитать некорректно раньше и конкретно, когда намерение было взято в моем OnNewIntent onNewIntent .

Я просто хочу добавить к ответу от @erickok, поскольку мне потребовалось несколько часов, чтобы понять это. Как указано в @jcesarmobile, вы гарантированно сможете получить имя и размер файла, а не полный путь.

Вы можете получить имя и размер следующим образом, а затем сохранить в временном файле:

 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(); } 
Intereting Posts