App的静默安装和卸载(有系统签名)
Android系统本身提供了安装卸载功能,但是api接口是@hide的,不是公开的接口,所以在应用级别是无法实现静默安装和卸载的,要实现静默安装和卸载需要是系统应用,要有系统签名和相应的权限
简单思路如下:
- 通过反射获得安装接口
installPackage
和 卸载接口deletePackage
- 在自己的包中引入两个接口
IPackageInstallObserver
和IPackageDeleteObserver
的空实现 - 调用安装卸载的方法,回调上面的两个接口
- 添加权限
android:sharedUserId="android.uid.system"
<uses-permission android:name="android.permission.DELETE_PACKAGES"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
- 进行系统签名
- 将应用push到系统中,作为系统应用
引入两个回掉的空实现
在自己应用的工程中新建一个包android.content.pm
,并添加两个文件
- IPackageDeleteObserver
package android.content.pm;
public interface IPackageDeleteObserver extends android.os.IInterface {
public abstract static class Stub extends android.os.Binder implements android.content.pm.IPackageDeleteObserver {
public Stub() {
throw new RuntimeException("Stub!");
}
public static android.content.pm.IPackageDeleteObserver asInterface(android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}
public android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}
public abstract void packageDeleted(java.lang.String packageName, int returnCode)
throws android.os.RemoteException;
}
- IPackageInstallObserver
package android.content.pm;
public interface IPackageInstallObserver extends android.os.IInterface {
public abstract static class Stub extends android.os.Binder implements android.content.pm.IPackageInstallObserver {
public Stub() {
throw new RuntimeException("Stub!");
}
public static android.content.pm.IPackageInstallObserver asInterface(android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}
public android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}
public abstract void packageInstalled(java.lang.String packageName, int returnCode)
throws android.os.RemoteException;
}
自定义接口回调
- OnPackagedObserver
public interface OnPackagedObserver {
void PackageInstalled(String packageName, int returnCode);
void PackageDeleted(String packageName,int returnCode);
}
实现方法
- 接口实现
private OnPackagedObserver onInstallOrDeleteObserver = new OnPackagedObserver() {
@Override
public void PackageInstalled(String packageName, int returnCode) {
Log.d("test","onPackageInstalled");
}
@Override
public void PackageDeleted(String packageName, int returnCode) {
Log.d("test","onPackageDeleted");
}
};
class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) throws RemoteException {
if (onInstallOrDeleteObserver != null) {
onInstallOrDeleteObserver.PackageInstalled(packageName, returnCode);
}
}
}
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(String packageName, int returnCode) throws RemoteException {
if (onInstallOrDeleteObserver != null) {
onInstallOrDeleteObserver.PackageDeleted(packageName, returnCode);
}
}
}
- 反射调用
卸载接口只需要提供要卸载的应用的包名
packagename
public static final int INSTALL_ALL_USERS = 0x00000040;
/**
* 静默卸载
*/
public void deleteApk(){
PackageManager pm = getPackageManager();
Class<?>[] uninstalltypes = new Class[] {String.class, IPackageDeleteObserver.class, int.class};
try {
Method uninstallmethod = pm.getClass().getMethod("deletePackage", uninstalltypes);
uninstallmethod.invoke(pm, "your packagename", new PackageDeleteObserver(), 0);
}catch (Exception e){
e.printStackTrace();
}
}
安装方法一
/**
* 静默安装
* @param filename
*/
public void installapk(File filename){
PackageManager pm = getPackageManager();
Class<?>[] types = new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class};
try {
Method method = pm.getClass().getMethod("installPackage", types);
Uri packageURI=Uri.fromFile(filename);
method.invoke(pm,packageURI, new PackageInstallObserver(), INSTALL_ALL_USERS, null);
}catch (Exception e){
e.printStackTrace();
}
}
安装方法二
/**
* 静默安装
* @param installPath
* @param packageName
*/
public void installApkInSilence(String installPath,String packageName) {
Class<?> pmService;
Class<?> activityTherad;
Method method;
try {
activityTherad = Class.forName("android.app.ActivityThread");
Class<?> paramTypes[] = getParamTypes(activityTherad, "getPackageManager");
method = activityTherad.getMethod("getPackageManager", paramTypes);
Object PackageManagerService = method.invoke(activityTherad);
pmService = PackageManagerService.getClass();
Class<?> paramTypes1[] = getParamTypes(pmService, "installPackageAsUser");
method = pmService.getMethod("installPackageAsUser", paramTypes1);
method.invoke(PackageManagerService, installPath, null, 0x00000040, packageName, getUserId(Binder.getCallingUid()));//getUserId
} catch (Exception e) {
e.printStackTrace();
}
}
private Class<?>[] getParamTypes(Class<?> cls, String mName) {
Class<?> cs[] = null;
Method[] mtd = cls.getMethods();
for (int i = 0; i < mtd.length; i++) {
if (!mtd[i].getName().equals(mName)) {
continue;
}
cs = mtd[i].getParameterTypes();
}
return cs;
}
public static final int PER_USER_RANGE = 100000;
public static int getUserId(int uid) {
return uid / PER_USER_RANGE;
}
这两个安装方法区别是调用时传入的地址不同。