[Android]应用内更新问题

embedded/2025/2/22 13:39:12/

问题:

以前的代码

    /*** @param url          下载连接* @param listener     下载监听*/fun download(url: String, onError: (Exception) -> Unit = {}, onProgress: (Int) -> Unit = {}, onDone: (File) -> Unit) {this.onProgress = onProgressval destFileDir = ctx.getExternalFilesDir("/DownloadFile")?.path ?: "/storage/emulate/0/DownloadFile" //储存下载文件的目录val dir = File(destFileDir)//dir.delete()if (!dir.exists()) dir.mkdirs()//保存文件的绝对路径val destFileName = getNameFromUrl(url)val file = File(dir, destFileName)if (file.exists()) file.deleteOnExit()okHttpClient.newCall(Request.Builder().url(url).build()).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {uiHandler.post { onError(e) }}@Throws(IOException::class)override fun onResponse(call: Call, response: Response) {response.body?.byteStream()?.let {val sum = response.body!!.contentLength()FileOutputStream(file).withInputStream(it) { p ->uiHandler.post {if (p >= sum) onDone(file)}}}}})}

权限会在andorid 12被废除,导致下载apk保存失败,导致应用无法更新

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 允许应用从外部存储设备读取数据。 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 允许应用写入内部存储。这通常用于保存临时文件或应用私有数据。 --><uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" /> <!-- 允许应用从内部存储读取数据。 --><uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> <!-- 允许应用录制音频。这对于语音记录应用或需要音频输入功能的应用非常重要。 -->

WRITE_EXTERNAL_STORAGE 权限在 Android 11(API 级别 30)及更高版本中被限制,并且在 Android 12(API 级别 31)中被彻底废弃。从 Android 11 开始,即使应用程序请求了 WRITE_EXTERNAL_STORAGE 权限,系统也会将其视为 READ_EXTERNAL_STORAGE 权限。因此,在 Android 11 及更高版本中,应用程序将无法直接写入外部存储,而必须通过其他方式来访问共享文件系统。

因此,从 Android 11 开始,开发者需要使用更安全的 Scoped Storage 或其他适当的方式来处理文件访问,以兼容最新的 Android 版本。

解决:

将apk保存到app的沙盒,这样就可以不需要权限,可以实现应用内更新.

package com.mofsaas.www.appupdateimport android.app.Activity
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import com.azhon.appupdate.listener.OnDownloadListenerAdapter
import com.azhon.appupdate.manager.DownloadManager
import com.mofsaas.www.BuildConfig
import com.mofsaas.www.R
import java.io.Fileprivate fun downMsg(progress: Int) = "下载进度:$progress%,请稍候"
fun Activity.startAppUpdate(apkUrl: String) {val ctx = thisval url =if (BuildConfig.DEBUG) "https://downv6.qq.com/qqweb/QQ_1/android_apk/Android_9.0.81_64.apk" else apkUrlif (url.isBlank()) {Toast.makeText(ctx, "无效的更新地址", Toast.LENGTH_SHORT).show()return}val builder = AlertDialog.Builder(ctx).apply {setTitle("下载安装包")setMessage(downMsg(0))setNegativeButton("取消") { dialog, _ ->dialog.dismiss()// 不在此处处理逻辑,统一到DialogFragment.onDismiss中处理}}val dlg = builder.create()fun downMsg(progress: Int) = "下载进度:$progress%,请稍候"val apkName = "appupdate.apk"// 可优化部分// 1.增加MD5值,减少下载次数val manager = DownloadManager.Builder(ctx).run {apkUrl(url)apkName(apkName)smallIcon(R.mipmap.ic_launcher)showBgdToast(false)onDownloadListener(object : OnDownloadListenerAdapter() {override fun start() {Toast.makeText(ctx, "开始下载新版本", Toast.LENGTH_SHORT).show()}override fun done(apk: File) {dlg.setTitle("安装")dlg.setMessage("开始安装,请允许相关授权")}override fun cancel() {dlg.dismiss()}override fun error(e: Throwable) {Toast.makeText(ctx, "下载发生错误", Toast.LENGTH_SHORT).show()dlg.dismiss()}override fun downloading(max: Int, progress: Int) {val curr = (progress / max.toDouble() * 100.0).toInt()//Toast.makeText(ctx, "downloading $max $progress ${downMsg(curr)}", Toast.LENGTH_SHORT).show()dlg.setMessage(downMsg(curr))}})build()}manager.download()dlg.apply {setCanceledOnTouchOutside(false)setCancelable(false)setOnDismissListener {manager.cancel()manager.release()Toast.makeText(ctx, "更新已取消", Toast.LENGTH_SHORT).show()}}dlg.show()
}


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

相关文章

爬虫运用--实战爬取高清图片

实战爬取高清图片 选择目标 首先选择一个网站&#xff0c;随便找了一下&#xff0c;发现这个网站质量还行 既然如此&#xff0c;直接开搞 分析结构 分析 随便查看一下&#xff0c;发现是通过index_{数字}.html控制图片显示的&#xff0c;这个就很好全部爬取下来了&#…

计算机毕业设计Python农产品推荐系统 农产品爬虫 农产品可视化 农产品大数据(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

关闭超时订单和七天自动确认收货+RabbitMQ规范

关闭超时订单 创建订单之后的一段时间内未完成支付而关闭订单的操作&#xff0c;该功能一般要求每笔订单的超时时间是一致的 TTL&#xff08;Time To Live&#xff09;存活时间&#xff0c;只能被设置为某个固定的值&#xff0c;不能更改&#xff0c;否则抛出异常 死信&#…

贪心算法-买卖股票的最佳时机

买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天 的价格。你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股 票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易…

✨2.快速了解HTML5的标签类型

✨✨HTML5 的标签类型丰富多样&#xff0c;每种类型都有其独特的功能和用途&#xff0c;以下是一些常见的 HTML5 标签类型介绍&#xff1a; &#x1f98b;结构标签 &#x1faad;<html>&#xff1a;它是 HTML 文档的根标签&#xff0c;所有其他标签都包含在这个标签内&am…

JUC并发—9.并发安全集合三

大纲 1.并发安全的数组列表CopyOnWriteArrayList 2.并发安全的链表队列ConcurrentLinkedQueue 3.并发编程中的阻塞队列概述 4.JUC的各种阻塞队列介绍 5.LinkedBlockingQueue的具体实现原理 6.基于两个队列实现的集群同步机制 1.并发安全的数组列表CopyOnWriteArrayList …

小米路由器 AX3000T 降级后无法正常使用,解决办法

问题描述 买了个 AX3000T 路由器&#xff0c;想安装 OpenWRT 或者 安装 Clash 使用&#xff0c;看教程说是需要降级到 v1.0.47 版本。 结果刷机之后路由器无法打开了&#xff0c;一直黄灯亮&#xff0c;中间灭一下&#xff0c;又是黄灯长亮&#xff0c;没有 WIFI 没有连接。以…

微软宣布 Windows 11 将不再免费升级:升级需趁早

大家都知道如果你现在是Windows 10 系统&#xff0c;其实可以免费升级到正版 Windows 11&#xff0c;只要你的电脑配置满足 TPM2.0要求。 而最近微软已经公布了 Windows 10 的最后支持时间&#xff0c;也就是今年10月14日&#xff0c;在这之后微软将不再对Windows 10负责&#…