安卓通过DownloadManager下载并安装Apk

实现功能

实现apk下载及安装.

注意

Apk下载文件的地址必须是https的,否则会失败(安卓默认网络连接都必须是https的)

实现效果

  • 操作界面效果图
    安卓通过DownloadManager下载并安装Apk_第1张图片
  • 下载中进度展示图(需要手动下拉顶部栏)
    安卓通过DownloadManager下载并安装Apk_第2张图片

主要代码

/**
 * apk下载工具类
 */
class DownloadUtils(private val context: Context) {
    //下载器
    private var downloadManager: DownloadManager? = null

    //下载的ID
    private var downloadId: Long = 0
    private var filePath: String? = null
    private lateinit var mFileName: String
    private var isDownloading = false

    //下载apk
    fun downloadAPK(url: String, fileName: String): Boolean {
        if (isDownloading) {
            return false
        }
        mFileName = fileName
        //创建下载任务
        val request = DownloadManager.Request(Uri.parse(url))
        //移动网络情况下是否允许漫游
        request.setAllowedOverRoaming(false)
        //在通知栏中显示,默认就是显示的
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
        request.setTitle(getAppName(context))
        request.setDescription("新版本下载中...")
        request.setVisibleInDownloadsUi(true)

        //设置下载的路径
        val file = File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName)
        if (file.exists()) {
            file.delete()
        }
        request.setDestinationUri(Uri.fromFile(file))
        filePath = file.absolutePath
        //获取DownloadManager
        if (downloadManager == null) downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
        if (downloadManager != null) {
            downloadId = downloadManager!!.enqueue(request)
        }
        isDownloading = true

        //注册广播接收者,监听下载状态
        context.registerReceiver(receiver,
                IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
        return true
    }

    //广播监听下载的各个状态
    private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            checkStatus(context)
        }
    }

    //检查下载状态
    private fun checkStatus(context: Context) {
        val query = DownloadManager.Query()
        //通过下载的id查找
        query.setFilterById(downloadId)
        val cursor = downloadManager!!.query(query)
        if (cursor.moveToFirst()) {
            val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
            when (status) {
                DownloadManager.STATUS_PAUSED -> {
                }
                DownloadManager.STATUS_PENDING -> {
                }
                DownloadManager.STATUS_RUNNING -> {
                }
                DownloadManager.STATUS_SUCCESSFUL -> {
                    //下载完成安装APK
                    installAPK()
                    cursor.close()
                    context.unregisterReceiver(receiver)
                    isDownloading = false
                }
                DownloadManager.STATUS_FAILED -> {
                    Toast.makeText(this.context, "下载失败", Toast.LENGTH_SHORT).show()
                    cursor.close()
                    context.unregisterReceiver(receiver)
                    isDownloading = false
                }
            }
        }
    }

    private fun installAPK() {
        val intent = Intent(Intent.ACTION_VIEW)
        // 由于没有在Activity环境下启动Activity,设置下面的标签
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        //Android 7.0以上要使用FileProvider
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val file = File(filePath)
            //参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致   参数3  共享的文件
            val apkUri = FileProvider.getUriForFile(context, "com.cxyzy.fileprovider", file)
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
        } else {
            intent.setDataAndType(Uri.fromFile(File(Environment.DIRECTORY_DOWNLOADS, mFileName)), "application/vnd.android.package-archive")
        }
        context.startActivity(intent)
    }

    private fun getAppName(context: Context): String {
        try {
            val packageManager = context.packageManager
            val packageInfo = packageManager.getPackageInfo(context.packageName, 0)
            val labelRes = packageInfo.applicationInfo.labelRes
            return context.resources.getString(labelRes)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
}

注:上述代码通过SoulPermission实现动态申请权限,需要在build.gradle中增加依赖:implementation 'com.qw:soulpermission:1.3.0'

  • 权限声明

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

完整源代码

https://gitee.com/cxyzy1/donwloadManagerDemo

你可能感兴趣的:(安卓)