该文档就是在android12系统上提供一个广播接收器,app端发送一个广播,并且带入apk的地址就可以实现安装
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
开始去定义那个广播,安装的广播
filter.addAction("com.android.packageinstaller.ACTION_SILENCE_INSTALL"); filter.addAction("android.intent.action.BOOT_COMPLETED");
然后就是收到安装的广播之后应该去干什么
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
@Override
public 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
代码路径 packages\apps\Settings\AndroidManifest.xml
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;
@Override
public 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) {
//卸载最高版本apk
installer.uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), pendingIntent.getIntentSender());
} else {
//卸载apk
installer.uninstall(packageName, pendingIntent.getIntentSender());
}
}
/**
* 显式卸载
*
* @param context
* @param packageName
*/
public static synchronized void uninstall(Context context, String packageName) {
//获取删除包名的URI
Uri uri = Uri.parse("package:" + packageName);
Intent intent = new Intent();
//设置我们要执行的卸载动作
intent.setAction(Intent.ACTION_DELETE);
//设置获取到的URI
intent.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. 会话id
int sessionId = createSession(packageInstaller, sessionParams);
Log.e(TAG, "sessionId " + sessionId);
if (sessionId != -1) {
//4. 将数据拷贝进session
boolean 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 (PackageInstaller
packageInstaller, PackageInstaller.SessionParams sessionParams){
int sessionId = -1;
try {
//根据sessionParams创建sessionId
sessionId = 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.Session
session = 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.Session
session = 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;
}
}