当前位置: 首页 > news >正文

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系统上提供一个广播接收器&#xff0c;app端发送一个广播&#xff0c;并且带入apk的地址就可以实现安装 1、广播注册 frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java 首先要导入的依赖 import android.app.P…...

基于电容电流前馈与电网电压全前馈的三相LCL并网逆变器谐波抑制Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Python数据攻略-Pandas与统计数据分析

统计学在数据分析中到底有多重要?在数据分析的世界里,统计学扮演着一角色。想象一下你是《三国志》游戏的数据分析师,任务是找出哪个武将最受玩家欢迎,哪些战役最具挑战性等。 你怎么做呢?这就需要统计学的力量了。 文章目录 基础统计方法描述性统计方差和标准差相关性和…...

【gcc】RtpTransportControllerSend学习笔记 1

本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。主要是大神文章: webrtc源码分析(8)-拥塞控制(上)-码率预估 的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。因为直接看大神的文章,自己啥也没记住,所以同时跟着看代码。跟…...

若依分离版-前端使用

1 执行 npm install --registryhttps://registry.npm.taobao.org&#xff0c;报错信息如下 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里的东西&#xff0c;输入App回车&#xff0c;调用生命周期 选项 - - - 重新打开此项目…...

卷积神经网络的发展历史-ResNet

ResNet的产生 2015 年&#xff0c;Kaiming He 提出了ResNet&#xff08;拿到了 2016 年 CVPR Best Paper Award&#xff09;&#xff0c;不仅解决了神经网络中的退化问题还在同年的ILSVRC和COCO 竞赛横扫竞争对手&#xff0c;分别拿下分类、定位、检测、分割任务的第一名。 R…...

基于瞬时无功功率ip-iq的谐波信号检测Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

node安装,nvm管理器

一、下载nvm&#xff0c;nvm-setup.exe https://github.com/coreybutler/nvm-windows/releases 二、配置NodeJS下载代理镜像&#xff08;可选&#xff09; 可以在NVM安装根目录下的setting.txt文件中&#xff0c;配置NodeJS下载代理镜像&#xff0c;解决在线安装NodeJS时速度…...

华为云云耀云服务器L实例评测|Ubuntu云锁防火墙安装搭建使用

华为云云耀云服务器L实例评测&#xff5c;Ubuntu安装云锁防火墙对抗服务器入侵和网络攻击 1.前言概述 华为云耀云服务器L实例是新一代开箱即用、面向中小企业和开发者打造的全新轻量应用云服务器。多种产品规格&#xff0c;满足您对成本、性能及技术创新的诉求。云耀云服务器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…...

趣味工具箱小程序源码

趣味工具箱小程序源码&#xff0c;支持功能去水印&#xff0c;精选壁纸&#xff0c;图片压缩&#xff0c;文字生成二维码&#xff0c;图片加水印&#xff0c;模拟来电&#xff0c;手持弹幕&#xff0c;掷骰子…等 使用小工具&#xff0c;一个小程序有几十个功能。 源码下载&am…...

互联网Java工程师面试题·Redis 篇·第二弹

目录 16、Redis 集群方案什么情况下会导致整个集群不可用&#xff1f; 17、Redis 支持的 Java 客户端都有哪些&#xff1f;官方推荐用哪个&#xff1f; 18、Jedis 与 Redisson 对比有什么优缺点&#xff1f; 19、Redis 如何设置密码及验证密码&#xff1f; 20、说说 Redis…...

FreeRTOS入门教程(信号量的概念及API函数使用)

文章目录 前言一、什么是信号量二、信号量种类和对比三、信号量和队列的区别四、信号量相关的函数1.创建函数2.删除函数3.获取和释放信号量函数 总结 前言 本篇文章正式带大家开始学习什么是信号量&#xff0c;并且掌握信号量函数的基本使用方法&#xff0c;并且将和队列进行一…...

简易版Pycharm(2023)+Conda开发环境配置教程

困 扰 不知道为什么&#xff0c;自从Pycharm更新了新的版本以后&#xff0c;在Pycharm中为项目工程配置Python解释器环境时&#xff0c;总是不能像以前那么方便的配置。 比如&#xff0c;当前Conda中有十个不同的开发环境&#xff0c;每个环境一个名称&#xff0c;比如&#x…...

深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(二)

前言 在上一篇深入浅出&#xff0c;SpringBoot整合Quartz实现定时任务与Redis健康检测&#xff08;一&#xff09;_往事如烟隔多年的博客-CSDN博客 文章中对SpringBoot整合Quartz做了初步的介绍以及提供了一个基本的使用例子&#xff0c;因为实际各自的需求任务不尽相同因此并…...

小谈设计模式(22)—单例模式

小谈设计模式&#xff08;22&#xff09;—单例模式 专栏介绍专栏地址专栏介绍 单例模式点睛所在优缺点分析优点确保只有一个实例全局访问点节省资源线程安全 缺点难以扩展对象的生命周期单一职责原则隐藏依赖关系 Java程序实例实例a分析实例b&#xff0c;更安全分析优化 ——“…...

华为OD机考算法题:分班

题目部分 题目分班难度易题目说明幼儿园两个班的小朋友在排队时混在了一起&#xff0c;每位小朋友都知道自己是否与前面一位小朋友是否同班&#xff0c;请你帮忙把同班的小朋友找出来。 小朋友的编号为整数&#xff0c;与前一位小朋友同班用 Y 表示&#xff0c;不同班用 N 表示…...

【gcc】RtpTransportControllerSend学习笔记 3:gcc

本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。本文使用的代码是m79 ,与大神有不同。2.4 Probe只会在一些特殊的时候才会进行探测(链路刚开始时, 码率不正常暴跌时)2.5 : 对发送的吞吐量…...

CSP-J第二轮试题-2019年-3题

文章目录 参考&#xff1a;总结 [CSP-J2019] 纪念品题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示答案 现场真题注意事项 参考&#xff1a; P5662 CSP-J2019纪念品 总结 本系列为CSP-J/S算法竞赛真题讲解&#xff0c;会按照年…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...