Android(java)高版本 DownloadManager 封装工具类,支持 APK 断点续传与自动安装

embedded/2025/3/17 12:54:29/

主要有以下优点

  1. 兼容高版本 Android:适配 Android 10 及以上版本的存储权限和安装权限。
  2. 断点续传:支持从断点继续下载。
  3. 下载进度监听:实时获取下载进度并回调。
  4. 错误处理:处理下载失败、网络异常等情况。
  5. 自动安装 APK:下载完成后自动安装 APK 文件。
  6. 通知栏进度:显示下载进度和状态。

优化后的 DownloadManager 工具类

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.core.content.FileProvider;
import java.io.File;public class DownloadUtils {private static final String TAG = "DownloadUtils";private static DownloadUtils instance;private DownloadManager downloadManager;private long downloadId;private Context context;private DownloadProgressListener progressListener;private DownloadObserver downloadObserver;private DownloadUtils(Context context) {this.context = context.getApplicationContext();downloadManager = (DownloadManager) this.context.getSystemService(Context.DOWNLOAD_SERVICE);}public static synchronized DownloadUtils getInstance(Context context) {if (instance == null) {instance = new DownloadUtils(context);}return instance;}/*** 下载文件** @param url      文件下载地址* @param fileName 保存的文件名* @param listener 下载进度监听器*/public void downloadFile(String url, String fileName, DownloadProgressListener listener) {this.progressListener = listener;// 创建下载请求DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));request.setTitle("文件下载");request.setDescription("正在下载文件...");request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);// 设置下载路径if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {// Android 10 及以上版本,使用应用专属目录request.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, fileName);} else {// Android 10 以下版本,使用公共下载目录request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);}// 支持断点续传request.setAllowedOverMetered(true); // 允许使用移动网络request.setAllowedOverRoaming(true); // 允许漫游时下载// 开始下载downloadId = downloadManager.enqueue(request);// 注册下载完成监听context.registerReceiver(downloadCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));// 注册下载进度监听if (progressListener != null) {downloadObserver = new DownloadObserver(new Handler(Looper.getMainLooper()), downloadId);context.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, downloadObserver);}}/*** 下载完成的广播接收器*/private final BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);if (id == downloadId) {if (progressListener != null) {progressListener.onDownloadComplete();}installApk(context);}}};/*** 安装 APK 文件*/private void installApk(Context context) {File apkFile;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {// Android 10 及以上版本,使用应用专属目录apkFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app-update.apk");} else {// Android 10 以下版本,使用公共下载目录apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "app-update.apk");}if (!apkFile.exists()) {Log.e(TAG, "APK 文件不存在");return;}// 使用 FileProvider 获取文件的 UriUri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFile);// 创建安装 IntentIntent installIntent = new Intent(Intent.ACTION_VIEW);installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 适配 Android 7.0 及以上版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);}// 适配 Android 8.0 及以上版本,允许安装未知来源的应用if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {if (!context.getPackageManager().canRequestPackageInstalls()) {// 跳转到设置页面,允许安装未知来源应用Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,Uri.parse("package:" + context.getPackageName()));intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);return;}}context.startActivity(installIntent);// 注销广播接收器和内容观察者context.unregisterReceiver(downloadCompleteReceiver);if (downloadObserver != null) {context.getContentResolver().unregisterContentObserver(downloadObserver);}}/*** 下载进度观察者*/private class DownloadObserver extends ContentObserver {private final long downloadId;public DownloadObserver(Handler handler, long downloadId) {super(handler);this.downloadId = downloadId;}@Overridepublic void onChange(boolean selfChange) {super.onChange(selfChange);queryDownloadProgress();}private void queryDownloadProgress() {DownloadManager.Query query = new DownloadManager.Query();query.setFilterById(downloadId);try (Cursor cursor = downloadManager.query(query)) {if (cursor != null && cursor.moveToFirst()) {int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));int bytesDownloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));int bytesTotal = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));if (status == DownloadManager.STATUS_RUNNING && bytesTotal > 0) {int progress = (int) ((bytesDownloaded * 100L) / bytesTotal);if (progressListener != null) {progressListener.onProgress(progress);}} else if (status == DownloadManager.STATUS_FAILED) {if (progressListener != null) {progressListener.onError("下载失败");}}}}}}/*** 下载进度监听器*/public interface DownloadProgressListener {void onProgress(int progress); // 下载进度(0-100)void onError(String message);  // 下载失败void onDownloadComplete();     // 下载完成}
}

使用示例

// 初始化工具类
DownloadUtils downloadUtils = DownloadUtils.getInstance(context);// 开始下载
downloadUtils.downloadFile("https://example.com/app-update.apk", "app-update.apk", new DownloadUtils.DownloadProgressListener() {@Overridepublic void onProgress(int progress) {Log.d(TAG, "下载进度: " + progress + "%");}@Overridepublic void onError(String message) {Log.e(TAG, "下载失败: " + message);}@Overridepublic void onDownloadComplete() {Log.d(TAG, "下载完成");}
});

优化点说明

  1. 兼容高版本 Android

    • 使用 FileProvider 提供文件的 Uri,适配 Android 7.0 及以上版本。
    • 适配 Android 8.0 及以上版本的未知来源应用安装权限。
  2. 断点续传

    • 通过 setAllowedOverMeteredsetAllowedOverRoaming 支持断点续传。
  3. 下载进度监听

    • 使用 ContentObserver 监听下载进度,并通过回调实时更新 UI。
  4. 错误处理

    • DownloadObserver 中检查下载状态,如果下载失败,通过 onError 回调通知调用方。
  5. 自动安装 APK

    • 下载完成后自动安装 APK 文件,适配高版本 Android 的权限要求。

总结

该工具类封装了 DownloadManager 的核心功能,并针对高版本 Android 进行了优化,支持断点续传、下载进度监听和自动安装 APK 文件。适用于需要文件下载和 APK 升级功能的 Android 应用。


http://www.ppmy.cn/embedded/173353.html

相关文章

【Linux】多线程互斥问题 和 锁

目录 一、资源共享问题: 1、数据不一致: 2、临界区与临界资源: 二、多线程模拟抢票: 出现问题: 三、锁: 1、锁的创建与销毁: 2、加锁操作: 2、解决抢票遗留问题&#xff1a…

BGP实验(二)路由反射器

一、拓扑图 二、实验需求 实现BGP路由互联互通 三、实验思路 由于iBGP间存在水平分割机制,因此R4和R5学习到R1的路由 应用全互联方法可以使iBGP都学习到路由,但网络规模较大时,会增加路由负担。 因此使用反射器(相当于中转站&…

设计模式-组件协作

组件协作 前言1. Template Method1.1 模式介绍1.2 代码案例1.2.1 问题代码1.2.2 重构代码 1.3 模式类图1.4 要点总结 2. Strategy2.1 模式介绍2.2 代码案例2.2.1 问题代码2.2.2 重构代码 2.3 模式类图2.4 要点总结 3. Observer/Event3.1 模式介绍3.2 问题引入3.3 解决方法3.4 模…

【AI大模型智能应用】Deepseek生成测试用例

在软件开发过程中,测试用例的设计和编写是确保软件质量的关键。 然而,软件系统的复杂性不断增加,手动编写测试用例的工作量变得异常庞大,且容易出错。 DeepSeek基于人工智能和机器学习,它能够依据软件的需求和设计文…

Ubuntu20.04安装运行DynaSLAM

目录 一、安装Anaconda 二、相关依赖库安装 1、boost安装 2、Eigen 3安装 3、opencv安装 4、Pangolin安装 三、配置Mask_RCNN环境 四、DynaSLAM编译 五、DynaSLAM运行 一、安装Anaconda 打开以下链接: Index of / 下载和自己系统匹配的安装包。这里下…

【从零开始学习计算机科学】软件工程(六)软件质量

【从零开始学习计算机科学】软件工程(六)软件质量 软件质量软件质量控制(QC)软件评审软件测试软件测试的基本原则结构化软件测试面向对象软件测试测试的方法软件质量保证(QA)QA与QC的区别在于:软件质量 软件工程中的重要的要求之一便是提高软件质量。 GB/T 11457-2006…

神聖的綫性代數速成例題3. 矩陣列數的極限、矩陣範數、行列式的計算

矩陣列數的極限:設矩陣序列,其中,若對每個都有,則稱矩陣序列收斂於矩陣,記作。矩陣範數:常用的矩陣範數有:行和範數,即矩陣每行元素絕對值之和的最大值。列和範數,即矩陣…

点点-一款超级强大AI生活搜索助手

今天得空,给兄弟萌墙裂推荐一款AI软件 ----点点! 前言 前两天刷小某书在评论区看到这么一句话:“在吃喝玩乐以及一些特别琐碎的很多方面,如果小某书搜不到的话,那就可能真的搜不到了”。这句话相信各位兄弟都深有同感,当代年轻人在互联网的状态之一是把小某书当某度用,…