MTK Android12静默安装接口
该文档就是在android12系统上提供一个广播接收器,app端发送一个广播,并且带入apk的地址就可以实现安装
1、广播注册
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
首先要导入的依赖
import android.app.PendingIntent;
import android.content.IntentSender;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
// import android.os.RemoteException;
import android.content.ComponentName;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;
import static android.content.pm.PackageInstaller.SessionParams.UID_UNKNOWN;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.net.Uri;
//import com.android.packageinstaller.InstallEventReceiver;
import com.android.server.policy.TemporaryFileManager;
import com.android.internal.content.PackageHelper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import android.os.Environment;
去定义一个变量
private final static SynchronousQueue<Intent> mInstallResults = new SynchronousQueue<>();
开始去定义那个广播,安装的广播
filter.addAction("com.android.packageinstaller.ACTION_SILENCE_INSTALL"); filter.addAction("android.intent.action.BOOT_COMPLETED");
然后就是收到安装的广播之后应该去干什么
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {mDefaultDisplayPolicy.setDockMode(intent.getIntExtra(Intent.EXTRA_DOCK_STATE,Intent.EXTRA_DOCK_STATE_UNDOCKED));}else if("com.android.packageinstaller.ACTION_SILENCE_INSTALL".equals(intent.getAction())){android.util.Log.e("yanf yim","enter install_app------");Intent mIntent1 = new Intent();mIntent1.setAction("com.android.install_app1");mIntent1.setComponent(new ComponentName("com.android.settings","com.android.settings.SDMountInstallReceiver"));String apkFilePath = intent.getStringExtra("apkFilePath");mIntent1.putExtra("path_name",apkFilePath);context.sendBroadcast(mIntent1);}
在这里就是去启动了Settings下的SDMountInstallReceiver
2、启动设置下的SDMountInstallReceiver
2.1 先去注册
代码路径 packages\apps\Settings\AndroidManifest.xml
<receiver android:name=".SDMountInstallReceiver"android:exported="true"><intent-filter android:priority="1000"> <action android:name="com.android.install_app1"/> <action android:name="com.android.install_app2"/> <action android:name="com.android.install_app3"/></intent-filter> </receiver>
<!--add end-->
2.2 安装的服务
packages\apps\Settings\src\com\android\settings\SDMountInstallReceiver.java
/*****接收广播,静默安装apk*/
package com.android.settings;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import java.io.File;
import android.os.Build;
import java.io.IOException;
import android.content.ContentValues;
import android.content.IntentFilter;
import android.util.Log;
import android.content.pm.PackageManager;
import android.os.storage.StorageManager;
import android.os.Environment;
import android.os.Bundle;
import android.os.SystemProperties;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.app.PendingIntent;
import android.content.IntentSender;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
// import android.os.RemoteException;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.util.Log;import androidx.core.content.FileProvider;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class SDMountInstallReceiver extends BroadcastReceiver {private static final String TAG="Install SDMountInstallReceiver";private static final String PROP_SD_EXTERNAL_PATH = "vold.path.external_sd";private String apksPath = " ";private Bundle bundleSimple;private PackageManager mPackageManager;@Overridepublic void onReceive(final Context context, Intent intent) {if ("com.android.install_app1".equals(intent.getAction())) {String pathName = intent.getStringExtra("path_name");android.util.Log.e("xnq", "enter SDMountInstallReceiver------1");installApk(context, pathName);android.util.Log.e("xnq", "enter SDMountInstallReceiver------2");}}/*** 显示安装** @param context* @param filePath*/public static synchronized void install(Context context, String filePath) {File apkFile = new File(filePath);Log.e(TAG, "apkPath " + apkFile.getAbsolutePath());if (!apkFile.exists()) {Log.e(TAG, "apk 不存在!");return;}Intent installApkIntent = new Intent();installApkIntent.setAction(Intent.ACTION_VIEW);installApkIntent.addCategory(Intent.CATEGORY_DEFAULT);installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//这里只适配了8.0需要有权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {boolean hasInstallPermission = context.getPackageManager().canRequestPackageInstalls();if (hasInstallPermission) {//通过FileProvider赋予apk访问权限Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFile);installApkIntent.setDataAndType(uri, "application/vnd.android.package-archive");installApkIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);if (context.getPackageManager().queryIntentActivities(installApkIntent, 0).size() > 0) {context.startActivity(installApkIntent);}}}}/*** 卸载apk** @param context* @param packageName*/public static synchronized void uninstallPackage(Context context, String packageName) {if (!isSystemSign(context)) {Log.e(TAG, "apk不具备系统签名,无法使用静默安装功能!");uninstall(context, packageName);return;}Intent intent = new Intent(context, SDMountInstallReceiver.class);intent.setAction(PackageInstaller.EXTRA_STATUS);//创建卸载广播意图PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);//获取安装程序PackageInstaller installer = context.getPackageManager().getPackageInstaller();//执行卸载操作if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//卸载最高版本apkinstaller.uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), pendingIntent.getIntentSender());} else {//卸载apkinstaller.uninstall(packageName, pendingIntent.getIntentSender());}}/*** 显式卸载** @param context* @param packageName*/public static synchronized void uninstall(Context context, String packageName) {//获取删除包名的URIUri uri = Uri.parse("package:" + packageName);Intent intent = new Intent();//设置我们要执行的卸载动作intent.setAction(Intent.ACTION_DELETE);//设置获取到的URIintent.setData(uri);context.startActivity(intent);}/*** 安装apk* @param context* @param filePath*/public static synchronized void installApk (Context context, String filePath){if (!isSystemSign(context)) {Log.e(TAG, "apk不具备系统签名,无法使用静默安装功能!");//install(context, filePath);return;}File apkFile = new File(filePath);Log.e(TAG, "apkPath " + apkFile.getAbsolutePath());if (!apkFile.exists()) {Log.e(TAG, "apk 不存在!");return;}//1. 获取包安装程序PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();//2. 安装参数PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);//设置大小sessionParams.setSize(apkFile.length());//3. 会话idint sessionId = createSession(packageInstaller, sessionParams);Log.e(TAG, "sessionId " + sessionId);if (sessionId != -1) {//4. 将数据拷贝进sessionboolean copySuccess = copyInstallFile(packageInstaller, sessionId, filePath);Log.e(TAG, "copySuccess " + copySuccess);if (copySuccess) {//5. 执行安装execInstallCommand(context, packageInstaller, sessionId);}}}/*** 创建sessionId** @param packageInstaller* @param sessionParams* @return*/private static int createSession (PackageInstallerpackageInstaller, PackageInstaller.SessionParams sessionParams){int sessionId = -1;try {//根据sessionParams创建sessionIdsessionId = packageInstaller.createSession(sessionParams);} catch (IOException e) {e.printStackTrace();}return sessionId;}/*** 拷贝apk文件,写入PackageInstaller.Session** @param packageInstaller* @param sessionId* @param apkFilePath* @return*/private static boolean copyInstallFile (PackageInstaller packageInstaller,int sessionId, String apkFilePath){InputStream in = null;OutputStream out = null;PackageInstaller.Session session = null;boolean success = false;try {File apkFile = new File(apkFilePath);//通过sessionId获取PackageInstaller.Sessionsession = packageInstaller.openSession(sessionId);//打开输入流out = session.openWrite("base.apk", 0, apkFile.length());//创建文件流in = new FileInputStream(apkFile);int total = 0, c;byte[] buffer = new byte[1024 * 1024];//读取文件流while ((c = in.read(buffer)) != -1) {total += c;out.write(buffer, 0, c);}//同步数据session.fsync(out);Log.i(TAG, "streamed " + total + " bytes");success = true;} catch (IOException e) {e.printStackTrace();} finally {try {if (out != null) {out.close();}if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}if (session != null) {session.close();}}return success;}/*** 执行安装** @param context* @param packageInstaller* @param sessionId* @return*/private static void execInstallCommand (Context context, PackageInstaller packageInstaller,int sessionId){PackageInstaller.Session session = null;try {//通过sessionId获取PackageInstaller.Sessionsession = packageInstaller.openSession(sessionId);//创建一个广播意图Intent intent = new Intent(context, SDMountInstallReceiver.class);intent.setAction(PackageInstaller.EXTRA_STATUS);//设置广播接受者PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);//执行安装命令,安装完成将发送广播通知session.commit(pendingIntent.getIntentSender());} catch (Exception e) {e.printStackTrace();} finally {if (session != null) {session.close();}}}/*** 根据包名判断app是否具有系统签名*/private static boolean isSystemSign (Context context){return context.getPackageManager().checkSignatures(Binder.getCallingUid(), android.os.Process.SYSTEM_UID) == PackageManager.SIGNATURE_MATCH;}}相关文章:
MTK Android12静默安装接口
该文档就是在android12系统上提供一个广播接收器,app端发送一个广播,并且带入apk的地址就可以实现安装 1、广播注册 frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java 首先要导入的依赖 import android.app.P…...
基于电容电流前馈与电网电压全前馈的三相LCL并网逆变器谐波抑制Simulink仿真
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Python数据攻略-Pandas与统计数据分析
统计学在数据分析中到底有多重要?在数据分析的世界里,统计学扮演着一角色。想象一下你是《三国志》游戏的数据分析师,任务是找出哪个武将最受玩家欢迎,哪些战役最具挑战性等。 你怎么做呢?这就需要统计学的力量了。 文章目录 基础统计方法描述性统计方差和标准差相关性和…...
【gcc】RtpTransportControllerSend学习笔记 1
本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。主要是大神文章: webrtc源码分析(8)-拥塞控制(上)-码率预估 的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。因为直接看大神的文章,自己啥也没记住,所以同时跟着看代码。跟…...
若依分离版-前端使用
1 执行 npm install --registryhttps://registry.npm.taobao.org,报错信息如下 npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: ktg-mes-ui3.8.2 npm ERR! Found: vue2.6.12 npm ERR! node_modu…...
微信小程序-2
微信开发文档 https://developers.weixin.qq.com/miniprogram/dev/framework/ 一、app.js中的生命周期函数与globalData(全局变量) 指南 - - - 小程序框架 - - - 注册小程序 删除app.js里的东西,输入App回车,调用生命周期 选项 - - - 重新打开此项目…...
卷积神经网络的发展历史-ResNet
ResNet的产生 2015 年,Kaiming He 提出了ResNet(拿到了 2016 年 CVPR Best Paper Award),不仅解决了神经网络中的退化问题还在同年的ILSVRC和COCO 竞赛横扫竞争对手,分别拿下分类、定位、检测、分割任务的第一名。 R…...
基于瞬时无功功率ip-iq的谐波信号检测Simulink仿真
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
node安装,nvm管理器
一、下载nvm,nvm-setup.exe https://github.com/coreybutler/nvm-windows/releases 二、配置NodeJS下载代理镜像(可选) 可以在NVM安装根目录下的setting.txt文件中,配置NodeJS下载代理镜像,解决在线安装NodeJS时速度…...
华为云云耀云服务器L实例评测|Ubuntu云锁防火墙安装搭建使用
华为云云耀云服务器L实例评测|Ubuntu安装云锁防火墙对抗服务器入侵和网络攻击 1.前言概述 华为云耀云服务器L实例是新一代开箱即用、面向中小企业和开发者打造的全新轻量应用云服务器。多种产品规格,满足您对成本、性能及技术创新的诉求。云耀云服务器L…...
C# OpenCvSharp 实现迷宫解密
效果 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Windows.Forms;namespace OpenCvSharp_实现迷宫解密 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e…...
趣味工具箱小程序源码
趣味工具箱小程序源码,支持功能去水印,精选壁纸,图片压缩,文字生成二维码,图片加水印,模拟来电,手持弹幕,掷骰子…等 使用小工具,一个小程序有几十个功能。 源码下载&am…...
互联网Java工程师面试题·Redis 篇·第二弹
目录 16、Redis 集群方案什么情况下会导致整个集群不可用? 17、Redis 支持的 Java 客户端都有哪些?官方推荐用哪个? 18、Jedis 与 Redisson 对比有什么优缺点? 19、Redis 如何设置密码及验证密码? 20、说说 Redis…...
FreeRTOS入门教程(信号量的概念及API函数使用)
文章目录 前言一、什么是信号量二、信号量种类和对比三、信号量和队列的区别四、信号量相关的函数1.创建函数2.删除函数3.获取和释放信号量函数 总结 前言 本篇文章正式带大家开始学习什么是信号量,并且掌握信号量函数的基本使用方法,并且将和队列进行一…...
简易版Pycharm(2023)+Conda开发环境配置教程
困 扰 不知道为什么,自从Pycharm更新了新的版本以后,在Pycharm中为项目工程配置Python解释器环境时,总是不能像以前那么方便的配置。 比如,当前Conda中有十个不同的开发环境,每个环境一个名称,比如&#x…...
深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(二)
前言 在上一篇深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(一)_往事如烟隔多年的博客-CSDN博客 文章中对SpringBoot整合Quartz做了初步的介绍以及提供了一个基本的使用例子,因为实际各自的需求任务不尽相同因此并…...
小谈设计模式(22)—单例模式
小谈设计模式(22)—单例模式 专栏介绍专栏地址专栏介绍 单例模式点睛所在优缺点分析优点确保只有一个实例全局访问点节省资源线程安全 缺点难以扩展对象的生命周期单一职责原则隐藏依赖关系 Java程序实例实例a分析实例b,更安全分析优化 ——“…...
华为OD机考算法题:分班
题目部分 题目分班难度易题目说明幼儿园两个班的小朋友在排队时混在了一起,每位小朋友都知道自己是否与前面一位小朋友是否同班,请你帮忙把同班的小朋友找出来。 小朋友的编号为整数,与前一位小朋友同班用 Y 表示,不同班用 N 表示…...
【gcc】RtpTransportControllerSend学习笔记 3:gcc
本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。本文使用的代码是m79 ,与大神有不同。2.4 Probe只会在一些特殊的时候才会进行探测(链路刚开始时, 码率不正常暴跌时)2.5 : 对发送的吞吐量…...
CSP-J第二轮试题-2019年-3题
文章目录 参考:总结 [CSP-J2019] 纪念品题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示答案 现场真题注意事项 参考: P5662 CSP-J2019纪念品 总结 本系列为CSP-J/S算法竞赛真题讲解,会按照年…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
