调用系统API,通过Intent启动com.android.packageinstaller(PackageInstaller.apk)系统app进行安装或升级;需要用户同意,并且有前台界面;
查看PackageInstaller在系统的存放位置:adb shell pm list packages -f com.android.packageinstaller或者adb shell pm list package -f | grep package(通过grep 过滤)
public void normal(String apkFilePath) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File uriFile = new File(apkFilePath);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(MyApplication.getApplication().getApplicationContext(), BuildConfig.APPLICATION_ID + ".fileprovider", uriFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(uriFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
if(MyApplication.getApplication().getApplicationContext().getPackageManager().queryIntentAc tivities(intent, 0).size() > 0) {
MyApplication.getApplication().getApplicationContext().startActivity(intent);
}
}
这里说的安装或升级可以是app自己对自己升级,也可以对其他app 升级或安装;静默升级或者安装,不同Android设备支持的方法不一样,需要自己测试,但是方法就这么几种;
第一种方法:利用ProcessBuilder
应用程序运行命令获取 Root权限,Android系统必须已经Root(获得ROOT权限)
如果没有没有获取root权限,会出现异常:SecurityException: Neither user 10058 nor current process has android.permission.INSTALL_PACKAGES.
条件:需要root权限
public String installSilently(String path) {
Log.d(TAG, "path" + path);
// 通过命令行来安装APK
String[] args = {"pm", "install", "-r", path};
String result = "";
// 创建一个操作系统进程并执行命令行操作
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = null;
InputStream errIs = null;
InputStream inIs = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read = -1;
process = processBuilder.start();
errIs = process.getErrorStream();
while ((read = errIs.read()) != -1) {
baos.write(read);
}
baos.write('\n');
inIs = process.getInputStream();
while ((read = inIs.read()) != -1) {
baos.write(read);
}
byte[] data = baos.toByteArray();
result = new String(data);
Log.d(TAG, "result" + result);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (errIs != null) {
errIs.close();
}
if (inIs != null) {
inIs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return result;
}
第二种方法:
利用Runtime.getRuntime().exec() 执行pm 安装命令
条件:需要系统已经root
public boolean silenceInstall(String path) {
// 进行资源的转移 将assets下的文件转移到可读写文件目录下
File file = new File(path);
boolean result = false;
Process process = null;
OutputStream out = null;
Log.i(TAG, "file.getPath():" + file.getPath());
if (file.exists()) {
System.out.println(file.getPath() + "==");
try {
process = Runtime.getRuntime().exec("su");
out = process.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(out);
// 获取文件所有权限
dataOutputStream.writeBytes("chmod 777 " + file.getPath()
+ "\n");
// 进行静默安装命令
dataOutputStream
.writeBytes("LD_LIBRARY_PATH=/vendor/lib:/system/lib pm install -r "
+ file.getPath());
dataOutputStream.flush();
// 关闭流操作
dataOutputStream.close();
out.close();
int value = process.waitFor();
// 代表成功
if (value == 0) {
Log.i(TAG, "安装成功!");
result = true;
// 失败
} else if (value == 1) {
Log.i(TAG, "安装失败!");
result = false;
// 未知情况
} else {
Log.i(TAG, "未知情况!");
result = false;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!result) {
Log.i(TAG, "root权限获取失败,将进行普通安装");
normal(path);
result = true;
}
}
return result;
}
第三种方法:
利用反射调用PackageManager.installPackage()
条件:需要app有系统权限,即清单文件AndroidManifest.xml中manifest标签需要添加android:sharedUserId="android.uid.system"属性;然后进行系统签名;有关系统签名需要Android设备厂家提供对用的系统版本的系统签名文件;有关系统签名的详细介绍在文章末尾;
申请权限
public static final int INSTALL_REPLACE_EXISTING = 0x00000002; //如果已经存在的包使用这个flag,例如升级
public static final int INSTALL_ALL_USERS = 0x00000040; //如果系统中没有安装过使用这个flag,例如安装其他的APP
public void installApp(String path) {
File file = new File(path);
PackageManager pm = MyApplication.getApplication().getPackageManager();
Class>[] types = new Class[]{Uri.class, IPackageInstallObserver.class, int.class, String.class};
try {
Method method = pm.getClass().getMethod("installPackage", types);
// method.invoke(pm,Uri.fromFile(file), new PackageInstallObserver(), INSTALL_ALL_USERS, null);
method.invoke(pm, Uri.fromFile(file), new PackageInstallObserver(), INSTALL_REPLACE_EXISTING, null);
} catch (Exception e) {
Log.d("安装失败", "");
e.printStackTrace();
}
}
静默卸载APP
public void deleteApp(String appPackage) {
PackageManager pm = MyApplication.getApplication().getPackageManager();
try {
Class>[] uninstalltypes = new Class[] {String.class, IPackageDeleteObserver.class, int.class};
Method uninstallmethod = pm.getClass().getMethod("deletePackage", uninstalltypes);
uninstallmethod.invoke(pm, appPackage, new PackageDeletedObserver(), 0);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private OnPackagedObserver onInstallOrDeleteObserver = new OnPackagedObserver() {
@Override
public void onPackageInstalled(String packageName, int returnCode) {
Log.d("test", "onPackageInstalled");
}
@Override
public void onPackageDeleted(String packageName, int returnCode) {
Log.d("test", "onPackageDeleted");
}
};
public class PackageInstallObserver extends IPackageInstallObserver.Stub {
@Override
public void packageInstalled(String s, int i) throws RemoteException {
if (onInstallOrDeleteObserver != null) {
onInstallOrDeleteObserver.onPackageInstalled(s, i);
}
}
}
public class PackageDeletedObserver extends IPackageDeleteObserver.Stub{
@Override
public void packageDeleted(String s, int i) throws RemoteException {
if (onInstallOrDeleteObserver != null) {
onInstallOrDeleteObserver.onPackageDeleted(s, i);
}
}
}
public interface OnPackagedObserver {
void onPackageInstalled(String packageName, int returnCode);
void onPackageDeleted(String packageName, int returnCode);
}
注意这个是系统提供的API接口,默认是隐藏的;所以在使用的时候,需要自己创建对应的api接口,这样才能通过编译;我这里已经编译成jar包了,需要的可以下载使用;
//传统卸载应用,即系统卸载app的API,需要用户同意,并且有前台界面;
String packageName = getPackageName();
Uri packageURI = Uri.parse("package:" + packageName);
//或者Uri packageURI = Uri.fromParts("package", "com.glapde", null);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
startActivity(uninstallIntent);
利用ProcessBuilder或者Runtime.getRuntime().exec() 执行一条pm卸载命令目前还没尝试成功过;但是通过PackageManager.deletePackage可以卸载成功,具体应用上面已经提供;
1,获取系统签名文件,一般需要Android设备厂家提供;
2,执行命令