欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

使用 Android DownloadManager 下载和安装 apk 文件

最编程 2024-04-27 07:01:58
...

一、创建下载任务,并开始下载

fun downLoadFileOnBackground(
        context: Context,
        downTitle: String,
        downDescription: String,
        fileUrl: String,
        fileName: String
    ): Long {
        LogUtils.i("文件路径:${fileName}")
        val request = DownloadManager.Request(Uri.parse(fileUrl))
        //下载中和下载完后都显示通知栏
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        //使用系统默认的下载路径 此处为应用内 /android/data/packages ,所以兼容7.0
        request.setDestinationInExternalFilesDir(
            context,
            Environment.DIRECTORY_DOWNLOADS,
            fileName
        )
        //通知栏标题
        request.setTitle(downTitle)
        //通知栏描述信息
        request.setDescription(downDescription)
        //设置类型为.apk
        request.setMimeType("application/vnd.android.package-archive");
        //获取下载任务ID
        val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        return dm.enqueue(request)
   }

该函数返回的是taskid
二、创建recever监听下载

class DownloadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
            installApk(context, id)
        } else if (intent.action.equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
            // DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
            //获取所有下载任务Ids组
            //long[] ids = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
            //点击通知栏取消所有下载
            //manager.remove(ids);
            //Toast.makeText(context, "下载任务已取消", Toast.LENGTH_SHORT).show();
            //处理 如果还未完成下载,用户点击Notification ,跳转到下载中心
            LogUtils.i("点击消息栏,开始安装")
            val viewDownloadIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
            viewDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            context.startActivity(viewDownloadIntent)
        }
    }

    private fun installApk(context: Context, downloadApkId: Long) {
        LogUtils.i("下载完成,开始安装")
        //判断是否允许安装未知来源安装包
        if (FileUtils.isCanInstallUnKnowSource()) {
            //安装apk
            val dManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
            val downloadFileUri = dManager.getUriForDownloadedFile(downloadApkId)
            FileUtils.installApkFile(context, null, downloadFileUri)
        } else {
            FileUtils.requestInstallUnKnowSource(context)
        }
    }
}

在activity中注册和取消注册

private val downLoadReceiver by lazy { DownloadReceiver() }


registerReceiver(downLoadReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
unregisterReceiver(downLoadReceiver)

三、fileProvider适配
manifest.xml中

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path" />
</provider>

xml文件夹下创建file_path.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--增加根目录配置,特别注意:此处的path要为空字符串-->
    <root-path
        name="root_path"
        path="" />
    <external-files-path
        name="files_download"
        path="Download" />
</paths>

因为安装apk文件用到一些系统文件下的内容,所以增加了root-path的访问,
由于未设置root-path的访问,可能在安装apk时提示解析安装包文件出现问题的提示

四、下载完成之后安装apk文件

fun installApkFile(context: Context, file: File?, fileUri: Uri?) {
        if (file == null && fileUri == null) {
            return
        }
        //打开安装界面
        val intent = Intent(Intent.ACTION_VIEW)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        if (file != null) {
            if (file.name.endsWith(".apk")) {
                val apkUri =
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        intent.addFlags(
                            Intent.FLAG_GRANT_READ_URI_PERMISSION
                        )
                        FileProvider.getUriForFile(
                            context,
                            context.packageName + ".fileProvider",
                            file
                        )
                    } else {
                        Uri.fromFile(file)
                    }
                intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
            }
        } else if (fileUri != null) {
            intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
        }
        context.startActivity(intent)

}

推荐阅读