使用DownloadManager从S3下载apk文件

11

有没有一种方法可以使用Android的DownloadManager从S3存储桶中下载文件?

我目前可以通过以下方式从Dropbox下载apk文件:

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));

request.addRequestHeader("Content-Type", "application/vnd.android.package-archive");
request.setMimeType("application/vnd.android.package-archive");

final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long id = manager.enqueue(request);

现在我想要做的是将"url"替换成我的亚马逊URL。但当我这样做时,下载进度会一直停留在0%并卡在那里。

有没有什么方法可以解决这个问题?

顺便说一下,我传入的亚马逊URL包含AWSAccessKeyIdExpiresSignature参数。URL看起来像这样:

https://bucket-name.s3-us-west-2.amazonaws.com/uploads/app/apk/22/app.apk?AWSAccessKeyId=""&Expires=""&Signature=""

你尝试过使用普通的HTTP而不是HTTPS吗?你尝试在你正在测试的设备或模拟器上的Web浏览器应用程序中访问URL了吗?你尝试过一个公共资源的URL(即不需要任何查询参数的URL)吗?这些只是一些可能缩小问题范围的想法。 - CommonsWare
@CommonsWare 我刚试了一些你建议的事情。如果我在我的S3存储桶中的文件上点击“公开”选项,下载就可以正常工作。这样就不需要参数了。所以我猜问题与我的AWS凭证有关?但是使用链接中的凭证,该文件确实可以在我的计算机浏览器中下载。 - theDazzler
那么我假设问题与我的AWS凭证有关?我从未尝试过使用带有查询参数的URL来使用DownloadManager。我认为DownloadManager应该支持它。查看解析的Uri和类似于getQuery()getQueryParameters()的内容,并确保您的值在途中没有被混淆。 - CommonsWare
@CommonsWare 好的,我刚看了解析后的Uri和getQueryParamters()以及getQuery()中的所有内容,一切似乎都很好。奇怪的是,我从DownloadManager那里没有收到任何错误或任何东西。它只是卡住了。我会觉得我会得到一些返回,例如401或403错误之类的东西。 - theDazzler
如果您能找到其他涉及查询参数(而非S3)的下载URL,请尝试一下。如果失败了,那么DownloadManager可能对查询参数有限制。如果成功了,那么在DownloadManager和S3之间握手时涉及到这些查询参数的某些东西就是罪魁祸首,尽管我不知道您该从哪里继续。 - CommonsWare
显示剩余4条评论
2个回答

4
它失败的原因是您设置了“Content-Type”标头。HTTP下载不需要此标头。但是,一旦设置,它必须成为预签名URL中的签名部分,根据AWS S3的要求。否则,您将看到403 Forbidden-“SignatureDoesNotMatch”错误。
快速解决方案是删除“Content-Type”标头。
request.addRequestHeader("Content-Type", "application/vnd.android.package-archive");

另一个解决方案是使用需要的标头生成预签名 URL。假设您确实想要设置内容类型,您可以将其添加到 GeneratePresignedUrlRequest 中,然后从中创建 URL。

GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key);
request.setContentType("application/vnd.android.package-archive");
URL url = s3Client.generatePresignedUrl(request);

请查看AmazonS3.generatePresignedUrl(GeneratePresignedUrlRequest)以了解更多详细信息。


哇,谢谢,这个方法很有效。你说这是“快速”解决方案。这个解决方案有什么问题我需要注意吗?有没有更好的“长期”解决方案?我对你的解决方案没有意见,只是想知道是否有任何需要注意的事项。 - theDazzler

1
你可以使用以下标头在请求中获取apk文件。
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:819457
Content-Type:application/octet-stream

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