Android app在后台静默升级,安装成功之后自动打开app

2024-05-12 18:48

本文主要是介绍Android app在后台静默升级,安装成功之后自动打开app,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、使用Android自带的DownloadManager远程下载APK;

    val handler = Handler()private fun downLoadApk(apkUrl: String) {//创建request对象val request: DownloadManager.Request =DownloadManager.Request(Uri.parse(apkUrl))//显示还是隐藏 隐藏加权限:DOWNLOAD_WITHOUT_NOTIFICATION//request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN)//设置通知栏的标题request.setTitle("下载")//设置通知栏的messagerequest.setDescription("正在下载.....")//设置下载文件类型request.setMimeType("application/vnd.android.package-archive")//设置文件存放目录request.setDestinationInExternalFilesDir(this,Environment.DIRECTORY_DOWNLOADS,"update.apk")//获取系统服务val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager//进行下载val id = downloadManager.enqueue(request)val runnable = object : Runnable {override fun run() {val cursor = downloadManager.query(DownloadManager.Query().setFilterById(id))cursor?.apply {if (moveToFirst()) {val title =getString(getColumnIndex(DownloadManager.COLUMN_TITLE))val uri =getString(getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))val current =getInt(getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))val total =getInt(getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))LogUtil.e(current.toString())//获取下载状态信息if (getInt(getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {//下载完成handler.removeCallbacksAndMessages(null)LogUtil.e("下载完成:$uri")val file = File(uri.substring(7)RootUtil.sinlenceInstallApk(file)}}}cursor?.close()handler.postDelayed(this, 1000)}}handler.postDelayed(runnable, 1000)}

二,下载完之后,通过封装的RootUtils工具类安装重启

object RootsUtils {/*** 判断手机是否有root权限*/private fun sysHasRootPerssion(): Boolean {var printWriter: PrintWriter?var process: Process? = nulltry {process = Runtime.getRuntime().exec("su")printWriter = PrintWriter(process.outputStream)printWriter.flush()printWriter.close()val value = process.waitFor()return returnResult(value)} catch (e: Exception) {e.printStackTrace()} finally {process?.destroy()}return false}/*** root下执行cmd的返回值*/private fun returnResult(value: Int): Boolean {// 代表成功return when (value) {0 -> {true}1 -> { // 失败false}else -> { // 未知情况false}}}/*** root下静默安装*/private fun rootSlienceInstallApk(apkPath: String): Boolean {var printWriter: PrintWriter?var process: Process? = nulltry {process = Runtime.getRuntime().exec("su")printWriter = PrintWriter(process.outputStream)printWriter.println("pm install -r $apkPath")printWriter.flush()printWriter.close()execLinuxCommand()val value = process.waitFor()return returnResult(value)} catch (e: Exception) {e.printStackTrace()} finally {process?.destroy()}return false}/*** 通过Linux延时执行重启*/private fun execLinuxCommand() {val cmd = "sleep 1; am start -n com.xx.xxx/.LunchActivity"//Runtime对象val runtime = Runtime.getRuntime()try {val localProcess = runtime.exec("su")val localOutputStream = localProcess.outputStreamval localDataOutputStream = DataOutputStream(localOutputStream)localDataOutputStream.writeBytes(cmd)localDataOutputStream.flush()LogUtil.e("设备准备重启")} catch (e: IOException) {e.printStackTrace()}}fun rootInstallApk(file: File) {if (!sysHasRootPerssion()) {LogUtil.e("系统尚无Root权限")return}LogUtil.i("系统有Root权限")if (!file.exists()) {LogUtil.e("尚无APK文件")return}//静默安装if (rootSlienceInstallApk(file.path)) {LogUtil.d("静默安装成功")} else {LogUtil.e("静默安装失败!!!")}}
}

三、使用的是Android7.1已经root的,经过反复测试,是可以静默安装并且安装成功之后自动重启成功的;

四、单个应用,在安装成功app之后,这个App的进程都被杀掉了,根本收不到广播重启打开了,如果非要使用广播打开的话,需要另外做一个无UI的App,做成双守护进程,把版本升级任务都交给它,通过它重启打开已安装的App,广播代码如下;

class BootReceiver : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {val action = intent.actionintent.dataString?.substring(8)?.apply {LogUtil.d("BootReceiver onReceive():接收到Intent.getAction() = " + intent.action + " , 包名 = " + intent.dataString)/*** 接收安装广播* android.intent.action.PACKAGE_ADDED*/if (action == Intent.ACTION_PACKAGE_ADDED) {LogUtil.d("BootReceiver onReceive():安装了:" + this + "包名的程序")}/*** 接收卸载广播* android.intent.action.PACKAGE_REMOVED*/if (action == Intent.ACTION_PACKAGE_REMOVED) {LogUtil.d("BootReceiver onReceive():卸载了:" + this + "包名的程序")}/*** 接收更新广播* android.intent.action.PACKAGE_REPLACED*/if (action == Intent.ACTION_PACKAGE_REPLACED) {LogUtil.d("BootReceiver onReceive():更新了:" + this + "包名的程序,context.getPackageName()=" + context.packageName)//更新的软件包名是否和我的工程一致if (this == context.packageName) {//更新完后打开val it = Intent()it.setClassName(this, "$this.xxxActivity") //启动类it.action = "android.intent.action.MAIN" //首个启动类actionit.addCategory("android.intent.category.LAUNCHER") //放入程序列表//it.addCategory("android.intent.category.HOME");                           //作为桌面,Home键打开,可做启动默认程序it.addCategory("android.intent.category.DEFAULT") //隐式打开,如果没main可有,如果main可有可无it.flags = Intent.FLAG_ACTIVITY_NEW_TASKcontext.startActivity(it)}}/*** 接收重启广播* android.intent.action.PACKAGE_REPLACED*/if (action == Intent.ACTION_PACKAGE_RESTARTED) {LogUtil.d("BootReceiver onReceive():重启了:" + this + "包名的程序")}/*** 接收开机广播* android.intent.action.BOOT_COMPLETED*/if (action == Intent.ACTION_BOOT_COMPLETED) {LogUtil.d("BootReceiver onReceive():仪器开机,开启了:" + this + "包名的程序")}}}
}
        <receiverandroid:name=".install.BootReceiver"android:label="@string/app_name"> <!-- app open/delete/upgrade/completed receiver --><intent-filter><action android:name="android.intent.action.PACKAGE_ADDED" /> <!-- add --><action android:name="android.intent.action.PACKAGE_REPLACED" /> <!-- update --><action android:name="android.intent.action.PACKAGE_REMOVED" /> <!-- delete --><action android:name="android.intent.action.PACKAGE_RESTARTED" /> <!-- restart --><action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- completed --><data android:scheme="package" /></intent-filter></receiver>

五、在静默安装之后执行重启代码

    /*** 执行此命令后:BootReceiver 监听到Intent.ACTION_PACKAGE_REPLACED,然后自启动* */fun rootStartApk(packageName: String, activityName: String): Boolean {val isSuccess = falsevar process: Process? = nulltry {process = Runtime.getRuntime().exec("su")val printWriter = PrintWriter(process.outputStream)printWriter.println("am start -n $packageName/.$activityName")printWriter.flush()printWriter.close()val value = process.waitFor()return returnResult(value)} catch (e: java.lang.Exception) {e.printStackTrace()} finally {process?.destroy()}return isSuccess}

 

这篇关于Android app在后台静默升级,安装成功之后自动打开app的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/983447

相关文章

虚拟机Centos7安装MySQL数据库实践

《虚拟机Centos7安装MySQL数据库实践》用户分享在虚拟机安装MySQL的全过程及常见问题解决方案,包括处理GPG密钥、修改密码策略、配置远程访问权限及防火墙设置,最终通过关闭防火墙和停止Net... 目录安装mysql数据库下载wget命令下载MySQL安装包安装MySQL安装MySQL服务安装完成

升级至三频BE12000! 华硕ROG魔盒Pro路由器首发拆解评测

《升级至三频BE12000!华硕ROG魔盒Pro路由器首发拆解评测》华硕前两天推出新一代电竞无线路由器——ROG魔盒Pro(StrixGR7Pro),该产品在无线规格、硬件配置及功能设计上实现全... 作为路由器行业的T1梯队厂商,华硕近期发布了新旗舰华硕ROG魔盒Pro,除了保留DIY属性以外,高达120

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads

SQL server数据库如何下载和安装

《SQLserver数据库如何下载和安装》本文指导如何下载安装SQLServer2022评估版及SSMS工具,涵盖安装配置、连接字符串设置、C#连接数据库方法和安全注意事项,如混合验证、参数化查... 目录第一步:打开官网下载对应文件第二步:程序安装配置第三部:安装工具SQL Server Manageme

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S