Android 系统下载 DownloadManager

news/2024/11/23 5:55:29/

 一、所需权限

<uses-permission android:name="android.permission.INTERNET" />
<!--如果下载的文件是apk,下载完安装需要该权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

二、简介

DownloadManager是Android提供的一个系统服务,通过这个服务,我们可以将下载文件的任务委托给系统进行,无需我们做太多的工作。

官网DownloadManager文档链接

 三、使用

1.创建

val request = DownloadManager.Request(Uri.parse(url))//设置允许使用的网络类型.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)//设置允许漫游.setAllowedOverRoaming(true)//设置文件格式.setMimeType(mimeType)//设置通知显示的时机// -下载中展示 VISIBILITY_VISIBLE(默认)// -下载中和完成时展示 VISIBILITY_VISIBLE_NOTIFY_COMPLETED// -下载完成时展示 VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION// -不展示 VISIBILITY_HIDDEN.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)//设置通知的标题.setTitle(getFileName(url))//设置通知的描述信息.setDescription(LOADING_TEXT).also {//设置下载地址context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()it.setDestinationInExternalFilesDir(context,Environment.DIRECTORY_DOWNLOADS,getFileName(url))}
downloadId = downloadManager?.enqueue(request)!!

2.注册广播,监听下载状态

val intentFilter = IntentFilter()
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
intentFilter.addAction(DownloadManager.ACTION_VIEW_DOWNLOADS)
intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED)
val downLoadReceiver = DownLoadReceiver()
context.registerReceiver(downLoadReceiver, intentFilter)

下载完成时,发送的广播。
对应的Action为:ACTION_DOWNLOAD_COMPLETE
下载过程中Notification被点击时发送的广播。
对应的Action为:ACTION_NOTIFICATION_CLICKED
查看所有下载情况的广播。
对应的Action为:ACTION_VIEW_DOWNLOADS

3.完整代码

以apk下载为例,下载完成后自动安装

package com.mine.common.toolsimport android.Manifest
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.mine.common.BuildConfig
import java.io.File
import java.lang.ref.WeakReference
import java.net.URI
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.set/*** DownLoadManager*/
object LocalDownloadManager {private const val HTTP = "http"private const val HTTPS = "https"private const val LOADING_TEXT = "正在下载"private const val TEMP_TEXT = "temp"private const val NET_SEPARATOR = "/"private const val FILE_PROVIDER_AUTHORITIES = "com.min.frame.fileProvider"private const val APK_MIME_TYPE = "application/vnd.android.package-archive"private val runningTask: MutableMap<String, Long> = mutableMapOf()private val bindReceivers: ConcurrentHashMap<WeakReference<AppCompatActivity>, DownLoadReceiver> =ConcurrentHashMap()private var downloadId = 0Lprivate var downloadManager: DownloadManager? = nullprivate var installPermissionLauncher: ActivityResultLauncher<String>? = nullprivate var activityResultLauncher: ActivityResultLauncher<Intent>? = nullprivate var currentUri: Uri? = null/*** 初始化(需要在onResume之前调用)*/fun init(activity: AppCompatActivity, autoBindReceiver: Boolean = true) {activity.lifecycleScope.launchWhenCreated {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {installPermissionLauncher = activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) {if (it) {goInstallAct(activity, currentUri)} else {with(Intent()) {this.data =Uri.parse("package:${activity.packageName}")if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {this.action =Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES} else {this.action =Settings.ACTION_SECURITY_SETTINGS}activityResultLauncher?.launch(this)}}}activityResultLauncher =activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {if (activity.packageManager.canRequestPackageInstalls()) {goInstallAct(activity, currentUri)} else {//文件已下载 未授予未知来源应用安装权限printLog("文件已下载,未授予未知来源应用安装权限")}}}}autoBindReceiver.takeIf { it }?.also {bindDownloadReceiver(activity)activity.lifecycle.addObserver(object : DefaultLifecycleObserver {override fun onDestroy(owner: LifecycleOwner) {super.onDestroy(owner)unbindDownloadReceiver(activity)printLog("onDestroy - current state = ${activity.lifecycle.currentState.name}")}})}}fun downLoad(context: Context, url: String, mimeType: String = APK_MIME_TYPE) {currentUri = nulldownloadManager?: (context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager).also {downloadManager = it}val netUrl = Uri.parse(url)if (!netUrl.scheme.equals(HTTP, true) && !netUrl.scheme.equals(HTTPS, true)) {return}val request = DownloadManager.Request(Uri.parse(url))//设置允许使用的网络类型.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)//设置允许漫游.setAllowedOverRoaming(true)//设置文件格式.setMimeType(mimeType)//设置通知显示的时机// -下载中展示 VISIBILITY_VISIBLE(默认)// -下载中和完成时展示 VISIBILITY_VISIBLE_NOTIFY_COMPLETED// -下载完成时展示 VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION// -不展示 VISIBILITY_HIDDEN.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)//设置通知的标题.setTitle(getFileName(url))//设置通知的描述信息.setDescription(LOADING_TEXT).also {//设置下载地址context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()it.setDestinationInExternalFilesDir(context,Environment.DIRECTORY_DOWNLOADS,getFileName(url))}downloadId = downloadManager?.enqueue(request)!!runningTask[url] = downloadId}fun bindDownloadReceiver(context: AppCompatActivity) {val intentFilter = IntentFilter()intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE)intentFilter.addAction(DownloadManager.ACTION_VIEW_DOWNLOADS)intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED)val downLoadReceiver = DownLoadReceiver()context.registerReceiver(downLoadReceiver, intentFilter)bindReceivers[WeakReference(context)] = downLoadReceiver}fun unbindDownloadReceiver(context: Context) {for (entry in bindReceivers.entries) {entry.key.also {if (it.get() == context) {context.unregisterReceiver(entry.value)bindReceivers.remove(entry.key)return}}}}private fun getFileName(url: String): String {val start = url.lastIndexOf(NET_SEPARATOR)val end = url.lengthreturn if (start != -1 && start != end) {url.substring(start + 1, url.length)} else {TEMP_TEXT}}/*** 下载状态广播*/class DownLoadReceiver : BroadcastReceiver() {override fun onReceive(context: Context?, intent: Intent?) {checkDownloadStatus(context, intent)}}/*** 安装页面*/fun goInstallAct(context: Context, uri: Uri?) {if (uri == null) returnwith(Intent()) {this.action = Intent.ACTION_VIEWthis.setDataAndType(uri, APK_MIME_TYPE)this.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION orIntent.FLAG_GRANT_WRITE_URI_PERMISSION orIntent.FLAG_ACTIVITY_NEW_TASKcontext.startActivity(this)}}private fun checkDownloadStatus(context: Context?, intent: Intent?) {when (intent?.action) {DownloadManager.ACTION_DOWNLOAD_COMPLETE -> {printLog("ACTION_DOWNLOAD_COMPLETE")val downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)val query = DownloadManager.Query()query.setFilterById(downloadId) //筛选下载任务,传入任务ID,可变参数downloadManager?.query(query).also { cursor ->if (cursor?.moveToFirst() == true) {val index = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)if (index < 0 || context == null)returnwhen (cursor.getInt(index)) {DownloadManager.STATUS_PAUSED -> {printLog("下载暂停")}DownloadManager.STATUS_PENDING -> {printLog("下载延迟")}DownloadManager.STATUS_RUNNING -> printLog("正在下载")DownloadManager.STATUS_SUCCESSFUL -> {val mimeType =downloadManager?.getMimeTypeForDownloadedFile(downloadId)for (entry in runningTask) {if (downloadId == entry.value) {runningTask.remove(entry.key)}break}val localUrlIndex =cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)val localUrl =if (localUrlIndex >= 0) cursor.getString(localUrlIndex) else nullif (mimeType == APK_MIME_TYPE) {localUrl?.also {val file = File(URI.create(localUrl))if (!file.exists()) returnval url = FileProvider.getUriForFile(context,FILE_PROVIDER_AUTHORITIES,file).also {currentUri = it}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {if (context.packageManager.canRequestPackageInstalls()) {goInstallAct(context, url)} else {installPermissionLauncher?.launch(Manifest.permission.REQUEST_INSTALL_PACKAGES)}} else {goInstallAct(context, url)}}}printLog("下载完成,文件 uri = $localUrl 文件类型 = $mimeType")}DownloadManager.STATUS_FAILED -> {for (entry in runningTask) {if (downloadId == entry.value) {runningTask.remove(entry.key)downloadManager?.remove(downloadId)}break}printLog("下载失败")}}}}}DownloadManager.ACTION_VIEW_DOWNLOADS -> {printLog("ACTION_VIEW_DOWNLOADS")}DownloadManager.ACTION_NOTIFICATION_CLICKED -> {printLog("ACTION_NOTIFICATION_CLICKED")}}}private fun printLog(msg: String) {if (BuildConfig.DEBUG) {android.util.Log.e(this@LocalDownloadManager::class.java.name, msg)}}
}

4.调用

初始化

override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)LocalDownloadManager.init(this)
}

启动下载任务


LocalDownloadManager.downLoad(this, "https://qd.shouji.qihucdn.com/nqapk/sjzs2_100000003_5f3fa999f0c1814618/221125/cf90dba7ce1833799ca369c2c5ca5b05/appstore-300100212.apk")


http://www.ppmy.cn/news/172413.html

相关文章

安卓平板排行榜_shopee虾皮台湾安卓市场, shopee虾皮直播下载

(将此文转发到朋友圈并截图发给小编微信&#xff1a;45677606 获取跨境电商免费学习大礼包。) 我做跨境电商也有六年的时间了&#xff0c;在电商这个行业也有自己的一些经验。经验也许没有其他大卖家丰富&#xff0c;但会将我知道的都进行分享。如果有不懂得亚马逊问题可以我(…

长尾词挖掘,挖掘有效长尾关键词的3个方法

长尾关键词的特征是比较长&#xff0c;往往是2-3个词组成&#xff0c;甚至是短语&#xff0c;存在于内容页面&#xff0c;除了内容页的标题&#xff0c;还存在于内容中。 长尾关键词带来的客户&#xff0c;转化为网站产品客户的概率比目标关键词高很多&#xff0c;因此长尾…

平板安装Ubuntu18.04教程

一、制作安装U盘 获取IOS镜像文件&#xff0c;请到官网下载镜像文件&#xff0c;需要注意&#xff0c;请勿下载国产修改版&#xff0c;不保证能够支持平板使用。请务必下载64位版本&#xff0c;32位不支持UEFI引导。 下载完成后下载U盘制作工具&#xff1a;Rufus 或 UltraISO 制…

平板电脑安装软件_看港澳节目,手机、平板、电脑,无需安装,一步搞定!

聪聪的那年微信公众号正式启用&#xff0c;聪聪将在《微信公众号》、《今日头条》、《西瓜视频》同步更新精彩软件&#xff0c;希望大家能关注聪聪&#xff0c;多给予支持关注&#xff0c;关注&#xff1a;聪聪的那年即可获取关注礼包&#xff0c;40款手机、电视、盒子软件&…

android平板电量,平板电池APP-平板电池下载v2.029 安卓版-西西软件下载

平板电池是一款电池壁纸的软件&#xff0c;它用更为“夸张”的方式来为你在桌面上进行电量上面的显示&#xff0c;无需下拉就能够直接的看到电池的电量&#xff0c;并且用更为优秀的方式来展示你电池的电量&#xff0c;如果你想要这种炫酷的方式的话&#xff0c;那么撞色款平板…

平板电脑 刷机王 linux,平板刷机王最新下载

选择这一款软件还是感觉比较靠谱的&#xff0c;毕竟经过了这么多年的用户反馈&#xff0c;在很多方面也解决了刚开始的小BUG&#xff0c;而且看下载量&#xff0c;一直都是比较受到欢迎的软件。相比见同类型的软件&#xff0c;能够看到很多独特的设定。 平板刷机王支持 1、自动…

2021-03-13

江湖救急&#xff0c;有人懂得nrf24L01和防火&#xff08;ds18b20,mQ-2&#xff09;防盗(h5-sr501)的流程图怎么画吗&#xff1f;

c语言实验四报告,湖北理工学院14本科C语言实验报告实验四数组

湖北理工学院14本科C语言实验报告实验四 数组.doc 实验四 数 组实验课程名C语言程序设计专业班级 14电气工程2班 学号 201440210237 姓名 熊帆 实验时间 5.12-5.26 实验地点 K4-208 指导教师 祁文青 一、实验目的和要求1. 掌握一维数组和二维数组的定义、赋值和输入输出的方法&…