Android DownloadManager 和 FileProvider
Android DownloadManager and FileProvider
我想使用 Android 的 DownloadManager 下载 pdf,然后允许用户使用他的 pdf 查看器应用打开它。
为此,我使用以下方式保存启动下载:
public String downloadFile(String url, String name) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Downloading file: " + name);
request.setTitle("My app name");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setMimeType("application/pdf");
Uri destinationUri = Uri.fromFile(new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), name+".pdf"));
request.setDestinationUri(destinationUri);
manager.enqueue(request);
return destinationUri.toString();
}
我正在保存 Uri 并使用它通过 PDF 查看应用打开 PDF:
public void openDownloadedFile(String uri) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(uri);
Uri uriForFile = FileProvider.getUriForFile(context.getApplicationContext(), context.getString(R.string.my_file_authority), file);
intent.setDataAndType(uriForFile, "application/pdf");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
}
我的 application
的清单文件包含以下提供商:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="@string/my_file_authority"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
而且我在provider_paths
中还有以下内容:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="my_pdfs"
path="."/>
<external-path
name="my_pdfs"
path="."/>
<files-path
name="my_pdfs"
path="."/>
</paths>
我知道那里有 2 个额外的元素,但我只是想确保我没有遗漏任何东西。
不幸的是,由于以下原因导致崩溃:
java.lang.IllegalArgumentException: Failed to find configured root that contains /file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:417)
一些额外的细节:
minSdkVersion 21
targetSdkVersion 27
我正在使用 Android O 在三星 S8 和 Android 模拟器上进行测试。
有人可以告诉我为什么会这样吗?
我怎么知道 Android 正在考虑我的 provider_paths?
谢谢!
PS:
- 我尝试为 DownloadManager 使用外部 public 目录,但它崩溃了,说它没有权限,即使在我的清单中我确实有 WRITE_EXTERNAL_STORAGE 权限并且我请求权限给用户,但对话框没有出现。
- 我也换了“.”从 provider_paths.xml 文件 "Download" 或 "Android" 甚至 "Android/data/{my_app_id}/files/Download/" 但我遇到了同样的崩溃
File file = new File(uri);
Uri
不是文件。
java.lang.IllegalArgumentException: Failed to find configured root that contains /file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
/file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
不是 Android 上的文件系统路径(AFAIK 也不是任何其他操作系统)。
解决这个问题:
将 new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), name+".pdf")
的结果从 destinationUri
实例化为 File
将 File
与 getUriForFile()
一起使用
我在这里参加派对有点晚了,但看到我也在为此苦苦挣扎,我想我会提供我终于找到的解决方案:经过大量的挖掘,我发现我们有小心 file://
和 content://
。两者都用作 Uris,但第一个公开访问文件(DownloadManager 方法),另一个通过权限访问文件(FileProvider 方法)。
我将总结一下我最终是如何做到的。就我而言,我在应用程序中使用下载的文件(从 mp3 中提取元数据并稍后播放)。我已经包含了检索文件供我使用的方法,因为这里也是,找出使用哪种方法访问文件的尝试错误很多。希望我能因此帮助其他也在尝试浏览这个 Uris 和权限迷宫的人。
正在使用 DownloadManager 下载文件
//set up the download manager and the file destination
final DownloadManager dlManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
String destination = Environment.getExternalStorageDirectory() + "*APPFOLDER*";
//ensure the folder exists before continuing
File file = new File(destination);
if (!file.exists())
file.mkdirs();
destination += "/" + "*FILENAME*";
final Uri destinationUri = Uri.parse("file://" + destination);
//create the download request
DownloadManager.Request dlRequest = new DownloadManager.Request(uri);
dlRequest.setDestinationUri(destinationUri);
final long dlId = dlManager.enqueue(dlRequest);
正在访问文件
File myPath = new File(Environment.getExternalStorageDirectory(), "*APPFOLDER*");
File myFile = new File(myPath, "*FILENAME*");
Uri myUri = FileProvider.getUriForFile(ctxt, ctxt.getApplicationContext().getPackageName() + ".file_provider", myFile);
ctxt.grantUriPermission(ctxt.getApplicationContext().getPackageName(), myUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(ctxt, myUri);
我想使用 Android 的 DownloadManager 下载 pdf,然后允许用户使用他的 pdf 查看器应用打开它。
为此,我使用以下方式保存启动下载:
public String downloadFile(String url, String name) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Downloading file: " + name);
request.setTitle("My app name");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setMimeType("application/pdf");
Uri destinationUri = Uri.fromFile(new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), name+".pdf"));
request.setDestinationUri(destinationUri);
manager.enqueue(request);
return destinationUri.toString();
}
我正在保存 Uri 并使用它通过 PDF 查看应用打开 PDF:
public void openDownloadedFile(String uri) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(uri);
Uri uriForFile = FileProvider.getUriForFile(context.getApplicationContext(), context.getString(R.string.my_file_authority), file);
intent.setDataAndType(uriForFile, "application/pdf");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
}
我的 application
的清单文件包含以下提供商:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="@string/my_file_authority"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
而且我在provider_paths
中还有以下内容:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="my_pdfs"
path="."/>
<external-path
name="my_pdfs"
path="."/>
<files-path
name="my_pdfs"
path="."/>
</paths>
我知道那里有 2 个额外的元素,但我只是想确保我没有遗漏任何东西。
不幸的是,由于以下原因导致崩溃:
java.lang.IllegalArgumentException: Failed to find configured root that contains /file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:417)
一些额外的细节:
minSdkVersion 21
targetSdkVersion 27
我正在使用 Android O 在三星 S8 和 Android 模拟器上进行测试。
有人可以告诉我为什么会这样吗? 我怎么知道 Android 正在考虑我的 provider_paths?
谢谢!
PS:
- 我尝试为 DownloadManager 使用外部 public 目录,但它崩溃了,说它没有权限,即使在我的清单中我确实有 WRITE_EXTERNAL_STORAGE 权限并且我请求权限给用户,但对话框没有出现。
- 我也换了“.”从 provider_paths.xml 文件 "Download" 或 "Android" 甚至 "Android/data/{my_app_id}/files/Download/" 但我遇到了同样的崩溃
File file = new File(uri);
Uri
不是文件。
java.lang.IllegalArgumentException: Failed to find configured root that contains /file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
/file:/storage/emulated/0/Android/data/{my_app_id}/files/Download/filename_of_pdf.pdf
不是 Android 上的文件系统路径(AFAIK 也不是任何其他操作系统)。
解决这个问题:
将
new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), name+".pdf")
的结果从destinationUri
实例化为File
将
File
与getUriForFile()
一起使用
我在这里参加派对有点晚了,但看到我也在为此苦苦挣扎,我想我会提供我终于找到的解决方案:经过大量的挖掘,我发现我们有小心 file://
和 content://
。两者都用作 Uris,但第一个公开访问文件(DownloadManager 方法),另一个通过权限访问文件(FileProvider 方法)。
我将总结一下我最终是如何做到的。就我而言,我在应用程序中使用下载的文件(从 mp3 中提取元数据并稍后播放)。我已经包含了检索文件供我使用的方法,因为这里也是,找出使用哪种方法访问文件的尝试错误很多。希望我能因此帮助其他也在尝试浏览这个 Uris 和权限迷宫的人。
正在使用 DownloadManager 下载文件
//set up the download manager and the file destination
final DownloadManager dlManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
String destination = Environment.getExternalStorageDirectory() + "*APPFOLDER*";
//ensure the folder exists before continuing
File file = new File(destination);
if (!file.exists())
file.mkdirs();
destination += "/" + "*FILENAME*";
final Uri destinationUri = Uri.parse("file://" + destination);
//create the download request
DownloadManager.Request dlRequest = new DownloadManager.Request(uri);
dlRequest.setDestinationUri(destinationUri);
final long dlId = dlManager.enqueue(dlRequest);
正在访问文件
File myPath = new File(Environment.getExternalStorageDirectory(), "*APPFOLDER*");
File myFile = new File(myPath, "*FILENAME*");
Uri myUri = FileProvider.getUriForFile(ctxt, ctxt.getApplicationContext().getPackageName() + ".file_provider", myFile);
ctxt.grantUriPermission(ctxt.getApplicationContext().getPackageName(), myUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(ctxt, myUri);