问题
Android DownloadManager API - 下载后如何打开文件?
解决方案
public void downloadFile(final Activity activity, final String url, final String fileName) {
try {
if (url != null && !url.isEmpty()) {
Uri uri = Uri.parse(url);
activity.registerReceiver(attachmentDownloadCompleteReceive, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setMimeType(getMimeType(uri.toString()));
request.setTitle(fileName);
request.setDescription("Downloading attachment..");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
dm.enqueue(request);
}
} catch (IllegalStateException e) {
Toast.makeText(activity, "Please insert an SD card to download file", Toast.LENGTH_SHORT).show();
}
}
private String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.getSingleton();
type = mime.getMimeTypeFromExtension(extension);
}
return type;
}
BroadcastReceiver attachmentDownloadCompleteReceive = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
openDownloadedAttachment(context, downloadId);
}
}
};
private void openDownloadedAttachment(final Context context, final long downloadId) {
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToFirst()) {
int downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
String downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
String downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
if ((downloadStatus == DownloadManager.STATUS_SUCCESSFUL) && downloadLocalUri != null) {
openDownloadedAttachment(context, Uri.parse(downloadLocalUri), downloadMimeType);
}
}
cursor.close();
}
private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType) {
if(attachmentUri!=null) {
if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme())) {
File file = new File(attachmentUri.getPath());
attachmentUri = FileProvider.getUriForFile(activity, "com.freshdesk.helpdesk.provider", file);;
}
Intent openAttachmentIntent = new Intent(Intent.ACTION_VIEW);
openAttachmentIntent.setDataAndType(attachmentUri, attachmentMimeType);
openAttachmentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
context.startActivity(openAttachmentIntent);
} catch (ActivityNotFoundException e) {
Toast.makeText(context, context.getString(R.string.unable_to_open_file), Toast.LENGTH_LONG).show();
}
}
}
初始化FileProvider详情
在AndroidManifest中声明FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.freshdesk.helpdesk.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path"/>
</provider>
请添加以下文件 "res -> xml -> file_path.xml"。
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="attachment_file" path="."/>
</paths>
注意
为什么要使用FileProvider
- 从Android 7.0开始,我们不能与其他应用程序共享FileUri。
- 使用“DownloadManager.COLUMN_LOCAL_URI”,我们只会得到FileUri,因此需要将其转换为ContentUri并与其他应用程序共享。
使用“DownloadManager.getUriForDownloadedFile(long id)”存在的问题
- 不要使用“DownloadManager.getUriForDownloadedFile(long id)” - 通过downloadId获取Uri以使用外部应用程序打开文件。
- 因为从Android 6.0和7.0开始,“getUriForDownloadedFile”方法返回本地uri(只能由我们的应用程序访问),我们无法与其他应用程序共享该uri,因为它们无法访问该uri(但在Android 7.1中已经修复了这个问题,请参见Android Commit Here)。
- 请参考Android源代码DownloadManager.java和Downloads.java
- 因此,始终使用列“DownloadManager.COLUMN_LOCAL_URI”获取Uri。
参考资料
- https://developer.android.com/reference/android/app/DownloadManager.html
- https://developer.android.com/reference/android/support/v4/content/FileProvider.html
DownloadManager.COLUMN_LOCAL_URI
来获取本地URI吗? - Gokul NCcom.freshdesk.helpdesk.provider
是从哪里来的?您需要明确知道要使用哪个应用程序打开文件吗?您可以使用默认应用程序打开吗? - SampoFLAG_GRANT_READ_URI_PERMISSION)
可以解决这个问题? - charlagdm.enqueue
的结果以便在BroadcastReceiver
中进行比较,不然我认为这会尝试打开其他应用程序启动的下载。 - Taylor Buchanan