DownloadManager 无法使用 Pie 下载到三星的外部存储
Posted
技术标签:
【中文标题】DownloadManager 无法使用 Pie 下载到三星的外部存储【英文标题】:DownloadManager fails to download to external storage on Samsung with Pie 【发布时间】:2019-08-30 17:14:25 【问题描述】:在 android 9 (Pie) 上的三星 Galaxy S9 和 S9+ 上,使用 Android 下载管理器将文件下载到外部存储失败。
下载适用于搭载 Android 8 的三星设备或其他搭载 Android 9 的设备(例如 Pixel 2)
我在清单中添加了以下权限:
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.INTERNET"
我还在运行时请求了 READ/WRITE_EXTERNAL_STORAGE 权限。
文件路径为:
/storage/4295-DDD5/Android/data/com.example.myapplication/files/filename.file
并且这个文件路径存在,我是使用 AndroidStudio 的设备文件资源管理器创建的
创建下载的方法:
public void downloadFile(String url, String filePath)
DownloadManager mDownloadManager =
(DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new
DownloadManager.Request(Uri.parse(url));
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE |
DownloadManager.Request.NETWORK_WIFI);
request.setVisibleInDownloadsUi(true);
request.setDestinationUri(Uri.parse("file://" + filePath));
mDownloadManager.enqueue(request);
预期的结果是将指定文件从 url 下载到 filePath,而不是我在日志中收到以下错误:
D/DownloadManager: [8616] Starting com.example.myapplication
W/DownloadManager: [8616] Stop requested with status FILE_ERROR: Failed to generate filename: java.io.IOException: Permission denied
D/DownloadManager: [8616] Finished with status WAITING_TO_RETRY
V/DownloadManager: MIME Type = application/octet-stream
I/DownloadManager: Download 8616 finished with status WAITING_TO_RETRY
I/DownloadManager: Notification Clear Download 1:com.example.myapplication
【问题讨论】:
我在 PocketMaps 存储库中发现了同样的问题:github.com/junjunguo/PocketMaps/issues/104 我也可以在带有 Android Pie 的 Pocophone F1 上重现此错误。 嗨!您对此问题有任何消息\解决方案吗?我面临与 Galaxy Tab A 和 Pie 完全相同的问题。 DownloadManager 只是不写入 sd 卡,只写入内部,Environment.getExternalStorageDirectory() 也返回内部路径。但我的代码也适用于其他安卓设备。 【参考方案1】:Oagar,过去帮助我的是阅读来自 https://commonsware.com/blog/archive.html 的所有 8 篇“外部存储之死”博文
我认为根本原因隐藏在这个:
文件路径是:/storage/4295-DDD5/Android/data/com.example.myapplication/files/filename.file 并且这个文件路径存在,我是使用AndroidStudio的设备文件资源管理器创建的
仅仅因为你创建了这个目录并看到它并不意味着你的应用能够写入它。 所以试着在你知道的地方写,确保你可以写文件。
希望这会对你有所帮助。
【讨论】:
文件路径选择通过以下方法ContextCompat.getExternalFilesDirs(context, null);
完成。错误在于 Android API 组件 DownloadManager 无法访问应用程序的“隔离存储沙箱”。如果我使用输入流:InputStream in = new URL(fileUrl).openStream(); Files.copy(in, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);
一切正常,文件下载到该位置。
***.com/users/1911218/oagar 我遇到了类似的问题,使用下载管理器,需要将文件存储在 SD 卡上。在 Android Pie 上遇到同样的错误。你能解释一下你是如何解决你的问题的吗?可以提供足够的代码吗?
这个答案在这种情况下没有帮助。这似乎实际上是三星最新固件中的一个错误,未经任何许可或@Oagar 代码。我的应用程序面临同样的问题,该应用程序在多种设备和 Android 4 到 10 上运行良好......除了三星最新的 Android 9。【参考方案2】:
我设法通过使用setDestinationInExternalFilesDir
(null
作为第二个参数)。
这应该将文件存储在与请求完全相同的位置,但实际实现似乎可以在三星设备上运行。我也没有请求任何许可 (*_EXTERNAL_STORAGE
)。
【讨论】:
这是个好消息!我知道问题不在于权限,而在于目录位置。 嗨,hrach,我遇到了问题中提到的确切问题!您能否详细说明 null 第二个参数如何帮助您?另外,由于您将其发送为空,您如何为下载的文件设置名称? 嗨@Sagar,我现在使用的调用是setDestinationInExternalFilesDir(context, null, fileName)
文件名只是该方法选择的目录中的文件名。您可以通过 cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
检索到的最终 URI
@hranch 试用了request.setDestinationInExternalFilesDir(mContext, null, filePath);
,它将文件放在此处:InternalStorage\Android\packageName\files\filepath
安装在搭载 Android 9 的三星 Galaxy S8 上。您还做过什么吗?问题是我们无法让 DownloadManager 将文件放在 ExternalStorage 上。【参考方案3】:
在你的 android 清单中添加这一行:
<application
...
android:usesCleartextTraffic="true"/>
(更多信息在official doc)
【讨论】:
以上是关于DownloadManager 无法使用 Pie 下载到三星的外部存储的主要内容,如果未能解决你的问题,请参考以下文章
W/DownloadManager:中止下载请求 17:无法创建目标文件 /storage/emulated/0/Ringtone/Fav_Ringtone.mp3