参考Android中实现静态的默认安装和卸载应用
使用系统自带的安装程序来实现程序的安装:
android自带了一个安装程序---/system/app/PackageInstaller.apk.大多数情况下,我们手机上安装应用都是通过这个apk来安装
代码使用:
/* 安装apk */ public static void installApk(Context context, String fileName) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.parse("file://" + fileName),"application/vnd.android.package-archive"); context.startActivity(intent); } /* 卸载apk */ public static void uninstallApk(Context context, String packageName) { Uri uri = Uri.parse("package:" + packageName); Intent intent = new Intent(Intent.ACTION_DELETE, uri); context.startActivity(intent); }同时,我们还可以监听apk文件的安装:
我们可以自定义一个广播接收者:
public void onReceive(Context context, Intent intent){ //接收安装广播 if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) { //TODO } //接收卸载广播 if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) { //TODO } }可是如果我们需要实现静默安装,这样显然是无法满足的,下面实现两种静默安装的方式:
通过运行命令来进行安装:
在adb shell中通过pm install -f apk文件路径
我们新建一个方法,用来在adb shell环境下执行pm install命令
final String path = "/storage/sdcard0/183/test/pertest.apk";
实现一个用来执行命令的方法:
public static String execCommand(String ...command) { Process process=null; InputStream errIs=null; InputStream inIs=null; String result=""; try { process=new ProcessBuilder().command(command).start(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int read = -1; errIs=process.getErrorStream(); while((read=errIs.read())!=-1){ baos.write(read); } inIs=process.getInputStream(); while((read=inIs.read())!=-1){ baos.write(read); } result=new String(baos.toByteArray()); if(inIs!=null) inIs.close(); if(errIs!=null) errIs.close(); process.destroy(); } catch (IOException e) { result = e.getMessage(); } return result; }其实,真正运行安装代码的只有这么一句话:process=new ProcessBuilder().command(command).start(); 剩下的只是为了返回给一个安装结果给用户
在mainactivity的onCreate方法中执行如下代码即可:
String result = execCommand("pm","install","-f",path);//安装apk String result = execCommand("pm","uninstall", "com.qihoo360.mobilesafe"); //卸载apk此时这个result就是系统返回给我们的一个安装或是卸载结果
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cmddemo" android:versionCode="1" android:versionName="1.0" android:sharedUserId="android.uid.system">表示该apk和系统程序运行在统一个进程中,即具有系统应用程序的权限:
此时运行我们的apk文件,会出现如下错误:
Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
Please check logcat output for more details.
Launch canceled!
说明我们需要对该apk进行系统签名,我们刚才已经手动运行了一边该工程,虽然不能直接运行,可是还是有用的,因为它会在该工程的bin目录下生成一个apk文件,接下来我们进行系统签名的时候就需要用到这个apk
对apk进行系统签名,我们需要以下三个文件:
对apk进行系统签名,我们需要以下三个文件:
platform.pk8,platform.x509.pem,signapk.jar这三个文件进行签名,注意这三个签名文件是在系统的源码中才有的:
platform.x509.pem和platform.pk8这两个文件是在/build/target/product/security/路径下
signapk.jar : /out/host/linux-x86/framework/signapk.jar
将三个文件拷贝到统一个目录中,然后将我们之前生成的apk同样拷贝到该目录下,然后进入该目录中,执行如下命令进行签名:
java -jar signapk.jar platform.x509.pem platform.pk8 CmdDemo.apk afterMo.apk
其中CmdDemo.apk是我们之前生命的apk,afterMo.apk是我们生成之后的签名的apk,此时安装这个afterMo.apk,就可以实现静默安装了。
注意这里有一个限制,就是我们只能在已知的平台上来进行静默安装,也就是说我们必须需要获得该平台的以上三个签名文件才可以的,因为现在的手机厂商都会进行自己的签名来确保安全性。
通过aidl实现静默安装
进入android源码目录
在android源码目录下有一个/frameworks/base/core/java/android/content/pm包
在这个包里边有以下几个文件:
IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl 和IPackageMoveObserver.aidl以及PackageManager.java文件
如果需要实现静默安装,我们需要在自己的工程里边新建一个包android.content.pm(这里需要注意,由于我们使用到了aidl,所以这里的包名必须和源码中的一样即"android.content.pm"),然后将我们需要用到的以上几个文件拷贝到该目录下:
因为用到了aidl,所以我们需要在bin目录下,新建一个aidl目录,在aidl目录下,继续新建以下目录:android/content/pm,在pm目录下,将我们需要用到的IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl 和IPackageMoveObserver.aidl这三个接口文件拷贝到该目录下
安装apk程序的代码:
String fileName = "/storage/sdcard0/183/test/plug.apk"; Uri uri = Uri.fromFile(new File(fileName)); int installFlags = 0; PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo("com.example.plug",PackageManager.GET_UNINSTALLED_PACKAGES); if(pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } } catch (NameNotFoundException e) { } MyPakcageInstallObserver observer = new MyPakcageInstallObserver(); pm.installPackage(uri, observer, installFlags, "com.example.plug"); /*静默安装回调*/ class MyPakcageInstallObserver extends IPackageInstallObserver.Stub{ @Override public void packageInstalled(String packageName, int returnCode) { if (returnCode == 1) { Log.e("DEMO","安装成功"); new ToastThread(InstallActivity.this,"安装成功").start(); }else{ Log.e("DEMO","安装失败,返回码是:"+returnCode); new ToastThread(InstallActivity.this,"安装失败,返回码是:"+returnCode).start(); } } }卸载程序的代码:
PackageManager pm = InstallActivity.this.getPackageManager(); IPackageDeleteObserver observer = new MyPackageDeleteObserver(); pm.deletePackage("com.example.plug", observer, 0); /* 静默卸载回调 */ class MyPackageDeleteObserver extends IPackageDeleteObserver.Stub { @Override public void packageDeleted(String packageName, int returnCode) { if (returnCode == 1) { Log.e("DEMO","卸载成功..."); new ToastThread(InstallActivity.this,"卸载成功...").start(); }else{ Log.e("DEMO","卸载失败...返回码:"+returnCode); new ToastThread(InstallActivity.this,"卸载失败...返回码:"+returnCode).start(); } } }另外需要在Manifest.xml文件中添加如下权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>同样需要添加android:sharedUserId="android.uid.system",来告诉系统我们的工程是系统进程