天天看点

android静默卸载,Android实践 -- Android静默安装和卸载

App的静默安装和卸载

Android系统本身提供了安装卸载功能,但是api接口是@hide的,不是公开的接口,所以在应用级别

是无法实现静默安装和卸载的,要实现静默安装和卸载需要是系统应用,要有系统签名和相应的权限

简单思路如下:

通过反射获得安装接口installPackage和 卸载接口 deletePackage

在自己的包中引入两个接口IPackageInstallObserver和IPackageDeleteObserver的空实现

调用安装卸载的方法,回调上面的两个接口

添加权限

进行系统签名

将应用push到系统中,作为系统应用

在PackageManager中的提供的接口如下

安装接口

// @SystemApi

public abstract void installPackage(

Uri packageURI, IPackageInstallObserver observer, int flags,

String installerPackageName);

卸载接口

// @SystemApi

public abstract void deletePackage(

String packageName, IPackageDeleteObserver observer, int flags);

引入两个回掉的空实现

在自己应用的工程中新建一个包android.content.pm,并添加两个文件

IPackageDeleteObserver.java

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.java

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.java

package com.example;

public interface OnPackagedObserver {

public void packageInstalled(String packageName, int returnCode);

public void packageDeleted(String packageName,int returnCode);

}

实现方法

反射接口

PackageManager pm = context.getPackageManager();

Class>[] types = new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class};

Class>[] uninstalltypes = new Class[] {String.class, IPackageDeleteObserver.class, int.class};

Method method = pm.getClass().getMethod("installPackage", types);

Method uninstallmethod = pm.getClass().getMethod("deletePackage", uninstalltypes);

实现回调接口

private OnPackagedObserver onInstalledPackaged;

class PackageInstallObserver extends IPackageInstallObserver.Stub {

public void packageInstalled(String packageName, int returnCode) throws RemoteException {

if (onInstalledPackaged != null) {

onInstalledPackaged.packageInstalled(packageName, returnCode);

}

}

}

class PackageDeleteObserver extends IPackageDeleteObserver.Stub {

public void packageDeleted(String packageName, int returnCode) throws RemoteException {

if (onInstalledPackaged != null) {

onInstalledPackaged.packageDeleted(packageName, returnCode);

}

}

}

实现

卸载接口只需要提供要卸载的应用的包名packagename ,安装提供了三个接口

public void uninstallPackage(String packagename) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {

uninstallmethod.invoke(pm, new Object[] {packagename, observerdelete, 0});

}

public void installPackage(String apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {

installPackage(new File(apkFile));

}

public void installPackage(File apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {

if (!apkFile.exists()) throw new IllegalArgumentException();

Uri packageURI = Uri.fromFile(apkFile);

installPackage(packageURI);

}

public void installPackage(Uri apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {

method.invoke(pm, new Object[] {apkFile, observer, INSTALL_REPLACE_EXISTING, null});

}

签名

生成一个apk文件,需要对这个apk文件进行系统签名,由于

是系统应用需要的权限,在开发应用时,如果加载AndroidManifest.xml

中会编译不过,需要先用工具 apktool 工具先把apk文件解压出来,用编辑器在AndroidManifest.xml中加入上面的两个权限,然后在用工具apktool重新打包

具体的使用方法参考 [Android实践 -- Apktool 的使用](http://www.jianshu.com/p/1896307da564)

解压

apktool d test.apk

修改之后,重新打包

apktool b test

签名之后的文件,需要在进行系统签名

具体的使用方法请参考 Android实践 -- 对apk进行系统签名

java -jar signapk.jar platform.x509.pem platform.pk8 test.apk test_signed.apk

将签名之后的文件 push到手机中,需要root权限

具体的代码实现

附录,安装卸载错误码速查

回调中的returnCode在PackageManager中的相关的定义如下:

安装错误码

public static final int INSTALL_SUCCEEDED = 1;

public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;

public static final int INSTALL_FAILED_INVALID_APK = -2;

public static final int INSTALL_FAILED_INVALID_URI = -3;

public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;

public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;

public static final int INSTALL_FAILED_NO_SHARED_USER = -6;

public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;

public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;

public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;

public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;

public static final int INSTALL_FAILED_DEXOPT = -11;

public static final int INSTALL_FAILED_OLDER_SDK = -12;

public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;

public static final int INSTALL_FAILED_NEWER_SDK = -14;

public static final int INSTALL_FAILED_TEST_ONLY = -15;

public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;

public static final int INSTALL_FAILED_MISSING_FEATURE = -17;

public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;

public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;

public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;

public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;

public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;

public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;

public static final int INSTALL_FAILED_UID_CHANGED = -24;

public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;

public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;

public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;

public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;

public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;

public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;

public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;

public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;

public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;

public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;

public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;

public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;

public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;

public static final int INSTALL_FAILED_USER_RESTRICTED = -111;

public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;

public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -113;

public static final int NO_NATIVE_LIBRARIES = -114;

public static final int INSTALL_FAILED_ABORTED = -115;

卸载错误码

public static final int DELETE_SUCCEEDED = 1;

public static final int DELETE_FAILED_INTERNAL_ERROR = -1;

public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;

public static final int DELETE_FAILED_USER_RESTRICTED = -3;

public static final int DELETE_FAILED_OWNER_BLOCKED = -4;

public static final int DELETE_FAILED_ABORTED = -5;