DownloadManager在Pie版本的三星手机上无法下载到外部存储

14

使用Android DownloadManager下载文件到外部存储在三星Galaxy S9、S9+上的Android 9(Pie)会失败。

对于安装有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 存储库中发现了相同的问题:https://github.com/junjunguo/PocketMaps/issues/104 同时,我可以在运行 Android Pie 的 Pocophone F1 上重现此错误。 - miracula
你好!关于这个问题,你有什么最新的消息或解决方案吗?我在使用Galaxy Tab A和Pie时遇到了完全相同的问题。DownloadManager只能写入内部存储,而不能写入SD卡,Environment.getExternalStorageDirectory()也返回内部路径。但是我的代码在其他Android设备上也可以正常工作。 - Kasem Anerin
3个回答

1
我使用setDestinationInExternalFilesDir(第二个参数为空)使其工作。

这应该会将文件存储在与请求的位置完全相同的位置,但实际实现似乎在三星设备上有效。此外,我没有请求任何权限(*_EXTERNAL_STORAGE)。


这是个好消息!我知道问题不在权限上,而是在目录位置上。 - Alex Bravo
嗨hrach,我遇到了与问题描述中完全相同的问题!你能详细说明一下空的第二个参数是如何帮助你的吗?还有,由于你将其发送为null,那么如何设置下载文件的名称呢? - Sagar
1
嗨,@Sagar,我现在使用的调用是setDestinationInExternalFilesDir(context, null, fileName),文件名只是方法选择的目录中的文件名。您可以通过cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))检索到最终URI。 - hrach
1
@hranch尝试使用request.setDestinationInExternalFilesDir(mContext, null, filePath);,它将文件放置在Samsung Galaxy S8上的此位置:InternalStorage\Android\packageName\files\filepath,该设备运行Android 9。您还做了其他事情吗?问题是我们无法让DownloadManager将文件放置在ExternalStorage上。 - Oagar

0

Oagar,过去帮助我的是阅读https://commonsware.com/blog/archive.html中的所有8篇“外部存储器的死亡”博客文章。

我认为根本原因就在这里:

文件路径为:/storage/4295-DDD5/Android/data/com.example.myapplication/files/filename.file,这个文件路径是存在的,我是使用AndroidStudio的设备文件浏览器创建的。

仅仅因为你创建了这个目录并且看到它,并不意味着你的应用程序能够写入它。所以尝试在你确定可以写入文件的地方进行写入。

希望这能帮到你。


3
文件路径的选择是通过以下方法 ContextCompat.getExternalFilesDirs(context, null); 完成的。问题在于 DownloadManager,一个 Android API 组件无法访问应用程序的“隔离存储沙盒”。如果我使用输入流:InputStream in = new URL(fileUrl).openStream(); Files.copy(in, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);,一切都正常,文件会被下载到指定位置。 - Oagar
https://stackoverflow.com/users/1911218/oagar 我遇到了类似的问题,使用下载管理器并需要将文件存储在SD卡上。在Android Pie上出现了相同的错误。您能否详细解释一下您是如何解决问题的?也许提供足够的代码? - Shoaib Mushtaq
这个答案在这种情况下没有帮助。这似乎实际上是三星最新固件中的一个错误,与任何权限或@Oagar代码无关。我正在使用我的应用程序遇到同样的问题,在许多设备和Android 4到10上都可以正常工作...除了三星最新的Android 9。 - Andy

0
在你的Android清单文件中添加这行代码:
<application
    ...
    android:usesCleartextTraffic="true"/>

(更多信息请参见官方文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接