当前位置: 首页 > article >正文

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

主要有以下优点

  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() {
        @Override
        public 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 获取文件的 Uri
        Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFile);

        // 创建安装 Intent
        Intent 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;
        }

        @Override
        public 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() {
    @Override
    public void onProgress(int progress) {
        Log.d(TAG, "下载进度: " + progress + "%");
    }

    @Override
    public void onError(String message) {
        Log.e(TAG, "下载失败: " + message);
    }

    @Override
    public 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.kler.cn/a/587455.html

相关文章:

  • C#结构体(Struct)详解
  • 学习MDA规范_9.CORBA(公共对象请求代理架构)‌
  • 「自动驾驶背后的数学:从传感器数据到控制指令的函数嵌套」—— 揭秘人工智能中的线性函数、ReLU 与复合函数
  • PostgreSQL数据库版本支持策略
  • camellia redis proxy v1.3.3对redis主从进行读写分离(非写死,自动识别故障转移)
  • CobaltStrike详细使用及Linux上线
  • 论Linux进程间通信
  • BGP实验(二)—路由反射器
  • 基于Spring Boot的小区疫情购物系统的设计与实现(LW+源码+讲解)
  • SOA(面向服务架构)与微服务架构的区别与联系
  • 企业为什么选择算力服务器?
  • MongoDB Vs Elasticsearch
  • 基于Python+SQLite实现(Web)验室设备管理系统
  • Linux 快捷键 | 终端快捷键 / 键盘快捷键
  • 9.贪心算法
  • C 语 言 --- 二 维 数 组 的 应 用
  • K8S学习之基础三十一:k8s中RBAC 的核心概念
  • 基于Matlab实现机械臂阻抗控制仿真
  • MinIo前后端实现
  • iptables练习笔记20250315