使用DownloadManager将文件下载到真实的SD卡而不是模拟存储。

5

我有一台Galaxy S4手机,我的问题是我无法使用DownloadManager将文件下载到SD卡上。在模拟存储中它可以正常工作,但是对于真实的SD卡却会出现以下错误:

java.lang.SecurityException: Destination must be on external storage: file:///mnt/extSdCard/Android/data/net.myApp/files/exercises/exec.mp4

这是我的代码:
DownloadManager dwlManager=(DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);

DownloadManager.Request dwlmRequest=new DownloadManager.Request(Uri.parse("http://cdn..."));
File destination = new File("/mnt/extSdCard/Android/data/net.myApp/files/exercises/exec.mp4");              

dwlmRequest.setDestinationUri(Uri.fromFile(destination));
dwlManager.enqueue(dwlmRequest); //<--- Here comes the error.

如果我将目标设置为:
File destination = new File(getExternalFilesDir(null), "exec.mp4");

代码工作得很好,因为目标地址位于模拟存储中。 此外,我也可以向SD卡创建文件,例如:

File f = new File("/mnt/extSdCard/Android/data/net.myApp/files/exercises/exec.mp4");
f.createNewFile();

它能够工作,但我无法使用下载管理器来下载到那个路径。

请帮忙。 我需要能够将文件下载到那个路径。

3个回答

3

这是不被支持的。即使你认为它们是指SD卡,也不能保证DownloadManager有权写入任意路径。此外,使用/mnt/extSdCard/的您自己的代码可能在您的设备上工作,但在许多设备上将无法工作,其中许多设备甚至都没有这样的目录。


这只是猜测,没有基于事实的答案。 - Chris Stratton
2
@ChrisStratton:如果你仔细阅读问题,DownloadManager会抛出一个特定的SecurityException。如果你阅读DownloadProvider源代码,你会发现checkFileUriDestination()抛出这个异常来“检查为DESTINATION_FILE_URI提供的文件URI是否有效”。因此,它不受支持。DownloadManager(或者更准确地说,DownloadProvider)是一个普通的应用程序,除非以超级用户权限运行,否则没有任何应用程序有权写入任意路径。 - CommonsWare
不,你混淆了应用程序级别的检查和权限。它们是两个完全不同的机制(实际上有三个,因为权限有两个执行阶段)。 - Chris Stratton
谢谢你们的帖子。这给了我一个很好的解释来解决我的问题。看起来我需要做一些巧妙的工作才能解决这个问题。我会将文件下载到模拟存储器中,然后像第二个答案建议的那样将其复制到所需路径。 - nolanic
@ChrisStratton: "问题在于你们(以及你)在应用程序级别上假设它可以和不能写入,而实际上没有在权限(Unix)级别上进行检查。" -- 我没有做出任何假设。我正在阅读 Java 代码并解释它的功能。如果您不喜欢当前的实现方式,请与 Google 联系。 - CommonsWare
显示剩余3条评论

2
根据这个链接:java.lang.SecurityException: 目标必须在外部存储上,DownloadManager无法将文件写入任意位置。但是可以使用“环境”常量将文件下载到外部存储中,在下载完成后将文件复制到所需位置,最后使用标准文件API删除原始文件。请保留HTML标签。

2
在解决这个问题的过程中,我找到了一种比下载后将文件复制到任意位置更优的解决方案。主要问题在于我设置了错误的SD卡路径。

它是:/mnt/extSdCard/Android/data...

但在三星Galaxy S4上应该是:/storage/extSdCard/Android/data...

默认下载管理器似乎可以很好地使用此路径作为下载目标。在下面的链接中,我找到了一个非常好的代码,用于检测不同设备的SD卡路径:http://www.javacodegeeks.com/2012/10/android-finding-sd-card-path.html

虽然看起来有点可疑,但对我来说,这似乎是最优的解决方案。


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