Android DownloadManager API - 下载后打开文件?

发布于 2024-12-02 04:54:00 字数 1556 浏览 1 评论 0原文

我遇到通过 DownloadManager API 成功下载后打开下载文件的问题。在我的代码中:

Uri uri=Uri.parse("http://www.nasa.gov/images/content/206402main_jsc2007e113280_hires.jpg");

Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
    .mkdirs();

lastDownload = mgr.enqueue(new DownloadManager.Request(uri)
    .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
                            DownloadManager.Request.NETWORK_MOBILE)
    .setAllowedOverRoaming(false)
    .setTitle("app update")
    .setDescription("New version 1.1")
    .setShowRunningNotification(true)
    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "a.apk"));

Cursor c=mgr.query(new DownloadManager.Query().setFilterById(lastDownload));

if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)) == 8) {
    try {
        mgr.openDownloadedFile(c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID)));
    } catch (NumberFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    }
}

问题是何时调用 if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))==8) 。我的状态为 -1 并有一个例外。有没有更好的方法,如何使用 DownloadManager API 打开下载的文件?在我的示例中,我正在下载一个大图像,在实际情况下,我将下载一个 APK 文件,并且我需要在 udpate 后立即显示安装对话框。

编辑:我发现 status=8 是在成功下载之后。您可能有不同的“检查成功下载”方法

谢谢

I am facing problem of opening downloaded file after successfull download via DownloadManager API. In my code:

Uri uri=Uri.parse("http://www.nasa.gov/images/content/206402main_jsc2007e113280_hires.jpg");

Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
    .mkdirs();

lastDownload = mgr.enqueue(new DownloadManager.Request(uri)
    .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
                            DownloadManager.Request.NETWORK_MOBILE)
    .setAllowedOverRoaming(false)
    .setTitle("app update")
    .setDescription("New version 1.1")
    .setShowRunningNotification(true)
    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "a.apk"));

Cursor c=mgr.query(new DownloadManager.Query().setFilterById(lastDownload));

if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)) == 8) {
    try {
        mgr.openDownloadedFile(c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID)));
    } catch (NumberFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    }
}

Problem is when is if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))==8) evoked. I got status -1 and an exception. Is there any better way, how to open downloaded files with DownloadManager API? In my example I am downloading a big image, in a real situation I would be downloading an APK file and I need to display an installation dialog immediately after udpate.

Edit: I figured out that status=8 is after successfull download. You might have different "checking successfull download" approach

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

韬韬不绝 2024-12-09 04:54:00

问题

Android DownloadManager API - 下载后打开文件?

解决方案

/**
 * Used to download the file from url.
 * <p/>
 * 1. Download the file using Download Manager.
 *
 * @param url      Url.
 * @param fileName File Name.
 */
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();
    }
}

/**
 * Used to get MimeType from url.
 *
 * @param url Url.
 * @return Mime Type for the given url.
 */
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;
}

/**
 * Attachment download complete receiver.
 * <p/>
 * 1. Receiver gets called once attachment download completed.
 * 2. Open the downloaded file.
 */
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);
        }
    }
};

/**
 * Used to open the downloaded attachment.
 *
 * @param context    Content.
 * @param downloadId Id of the downloaded file to open.
 */
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();
}

/**
 * Used to open the downloaded attachment.
 * <p/>
 * 1. Fire intent to open download file using external application.
 *
 * 2. Note:
 * 2.a. We can't share fileUri directly to other application (because we will get FileUriExposedException from Android7.0).
 * 2.b. Hence we can only share content uri with other application.
 * 2.c. We must have declared FileProvider in manifest.
 * 2.c. Refer - https://developer.android.com/reference/android/support/v4/content/FileProvider.html
 *
 * @param context            Context.
 * @param attachmentUri      Uri of the downloaded attachment to be opened.
 * @param attachmentMimeType MimeType of the downloaded attachment.
 */
private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType) {
    if(attachmentUri!=null) {
        // Get Content Uri.
        if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme())) {
            // FileUri - Convert it to contentUri.
            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”< /strong>

<?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

  1. 从 Android 7.0 开始,我们无法与其他应用程序共享 FileUri。
  2. 使用“DownloadManager.COLUMN_LOCAL_URI”我们只能得到 FileUri,因此我们需要将其转换为 ContentUri 和 ContentUri。与其他应用程序共享。

使用“DownloadManager.getUriForDownloadedFile(long id)”的问题

  1. 不要使用“DownloadManager.getUriForDownloadedFile(long id)” - 从 downloadId 获取 Uri 以使用外部应用程序打开文件。
  2. 因为从 Android 6.0 开始7.0“getUriForDownloadedFile”方法返回本地 uri(只能由我们的应用程序访问),我们无法与其他应用程序共享该 uri,因为它们无法访问该 uri(但在 Android 7.1 中已修复 请参阅此处的 Android 提交)。
  3. 参考Android源码 DownloadManager.java & Downloads.java
  4. 因此始终使用 Column “DownloadManager.COLUMN_LOCAL_URI”来获取 Uri。

参考

  1. https://developer.android.com/reference /android/app/DownloadManager.html
  2. https://developer.android.com/reference/android/support/v4/content/FileProvider.html

Problem

Android DownloadManager API - opening file after download?

Solution

/**
 * Used to download the file from url.
 * <p/>
 * 1. Download the file using Download Manager.
 *
 * @param url      Url.
 * @param fileName File Name.
 */
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();
    }
}

/**
 * Used to get MimeType from url.
 *
 * @param url Url.
 * @return Mime Type for the given url.
 */
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;
}

/**
 * Attachment download complete receiver.
 * <p/>
 * 1. Receiver gets called once attachment download completed.
 * 2. Open the downloaded file.
 */
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);
        }
    }
};

/**
 * Used to open the downloaded attachment.
 *
 * @param context    Content.
 * @param downloadId Id of the downloaded file to open.
 */
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();
}

/**
 * Used to open the downloaded attachment.
 * <p/>
 * 1. Fire intent to open download file using external application.
 *
 * 2. Note:
 * 2.a. We can't share fileUri directly to other application (because we will get FileUriExposedException from Android7.0).
 * 2.b. Hence we can only share content uri with other application.
 * 2.c. We must have declared FileProvider in manifest.
 * 2.c. Refer - https://developer.android.com/reference/android/support/v4/content/FileProvider.html
 *
 * @param context            Context.
 * @param attachmentUri      Uri of the downloaded attachment to be opened.
 * @param attachmentMimeType MimeType of the downloaded attachment.
 */
private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType) {
    if(attachmentUri!=null) {
        // Get Content Uri.
        if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme())) {
            // FileUri - Convert it to contentUri.
            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();
        }
    }
}

Initialize FileProvider Details

Decleare FileProvider in AndroidManifest

<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>

Add the following file "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>

Note

Why Use FileProvider

  1. From Android 7.0 we can't share FileUri with other appliction.
  2. Using "DownloadManager.COLUMN_LOCAL_URI" we will get only FileUri hence we need to convert it into ContentUri & share with other application.

Provblem with using "DownloadManager.getUriForDownloadedFile(long id)"

  1. Don't use "DownloadManager.getUriForDownloadedFile(long id)" - To get Uri from downloadId to open the file using external application.
  2. Because from Android 6.0 & 7.0 "getUriForDownloadedFile" method returns local uri (Which can be accessed only by our application), we can't share that Uri with other application because they can't access that uri (But it is fixed in Android 7.1 see Android Commit Here).
  3. Refere Android source code DownloadManager.java & Downloads.java
  4. Hence always use Column "DownloadManager.COLUMN_LOCAL_URI" to get Uri.

Reference

  1. https://developer.android.com/reference/android/app/DownloadManager.html
  2. https://developer.android.com/reference/android/support/v4/content/FileProvider.html
前事休说 2024-12-09 04:54:00

下载完成后,您需要注册一个接收器:

registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

和一个 BroadcastReciever 处理程序

BroadcastReceiver onComplete=new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        // Do Something
    }
};

Buy 而不是我抄袭所有内容,我建议您检查 这个

编辑:

作为一个建议,我还不建议使用 API 9:http://developer.android.com/resources/dashboard/platform-versions.html

有很多方法可以解决这个问题,通过创建你自己的下载处理程序,就像我所做的那样,因为我们不想疏远我们的大多数 Android 用户群,为此你需要:
创建处理文件下载的 AsyncTask

我会建议创建某种下载对话框(如果你说它是一个大文件,我会让它出现在通知区域中)。

然后您需要处理文件的打开:

protected void openFile(String fileName) {
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setDataAndType(Uri.fromFile(new File(fileName)),
            "MIME-TYPE");
    startActivity(install);
}

You need to register a reciever for when the download is complete:

registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

and a BroadcastReciever handler

BroadcastReceiver onComplete=new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        // Do Something
    }
};

Buy instead of me ripping off everything, I suggest you'll check this out.

EDIT:

Just as a suggestion, I wouldn't recommend using API 9 just yet: http://developer.android.com/resources/dashboard/platform-versions.html

There are ways around this, by creating your very own download handler, like I did, because we didn't want to alienate most of our android's user base, for that you'll need:
Create AsyncTask which handles the file download.

and i'll recommend to create a download dialog of some sort (if you say it's a big file, i'd make it appear in the notification area).

and than you'll need to handle the opening of the file:

protected void openFile(String fileName) {
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setDataAndType(Uri.fromFile(new File(fileName)),
            "MIME-TYPE");
    startActivity(install);
}
心凉 2024-12-09 04:54:00

对我来说,帮助添加了 Intent.FLAG_GRANT_READ_URI_PERMISSION ,我已经忘记了

For me, helped adding Intent.FLAG_GRANT_READ_URI_PERMISSION ,which i have forgotten

我不咬妳我踢妳 2024-12-09 04:54:00

对于 Kotlin,您可以轻松地使用 URL.openStream() 方法来读取文件并将其保存在目录中。

如果你想做更多更奇特的事情,比如后台线程。
您应该查看 Elye 在 Medium 上的文章。

https://medium.com/移动应用开发发布/download-file-in-android-with-kotlin-874d50bccaa2

private fun downloadVcfFile() {
    CoroutineScope(Dispatchers.IO).launch {
        val url = "https://srv-store5.gofile.io/download/JXLVFW/vcard.vcf"
        val path = "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/contacts.vcf"

        URL(url).openStream().use { input ->
            FileOutputStream(File(path)).use { output ->
                input.copyTo(output)

                val file = File(path)
                file.createNewFile()
                onMain { saveVcfFile(file) }
            }
        }
    }
}

For Kotlin, you can easily just use the URL.openStream() method to read and save your file in your directory.

If you want to do more fancier, like background threads.
You should checkout Elye's article on Medium.

https://medium.com/mobile-app-development-publication/download-file-in-android-with-kotlin-874d50bccaa2

private fun downloadVcfFile() {
    CoroutineScope(Dispatchers.IO).launch {
        val url = "https://srv-store5.gofile.io/download/JXLVFW/vcard.vcf"
        val path = "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/contacts.vcf"

        URL(url).openStream().use { input ->
            FileOutputStream(File(path)).use { output ->
                input.copyTo(output)

                val file = File(path)
                file.createNewFile()
                onMain { saveVcfFile(file) }
            }
        }
    }
}
眼眸里的那抹悲凉 2024-12-09 04:54:00

请记住将 添加到您的 AndroidMannifest.xml 文件中

remember add <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> to your AndroidMannifest.xml file

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文