android 开发实现静默安装
参考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文件的安装:
在我们的系统安装和卸载程序的时候,系统会发送以下广播:
在安装和卸载完后,android系统会发一个广播
android.intent.action.PACKAGE_ADDED(安装)
android.intent.action.PACKAGE_REMOVED(卸载)
我们可以自定义一个广播接收者:
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);//安装apkString result = execCommand("pm","uninstall", "com.qihoo360.mobilesafe"); //卸载apk此时这个result就是系统返回给我们的一个安装或是卸载结果
注意需要在Manifest.xml中添加如下权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
注意android系统出于安全考虑,我们是不能进行静默安装的,那么我们需要给该Manifest.xml中添加如下一句:
android:sharedUserId="android.uid.system"
<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",来告诉系统我们的工程是系统进程
最后运行该工程,同样会出现如下错误:
[2015-04-06 11:05:51 - androidauto] Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
[2015-04-06 11:05:51 - androidauto] Please check logcat output for more details.
[2015-04-06 11:05:51 - androidauto] Launch canceled!
此时我们需要对之前bin目录生成的apk进行系统签名:
java -jar signapk.jar platform.x509.pem platform.pk8 需要签名的apk 签名之后的apk
此时签名之后的apk是拥有系统权限的,此时这个apk就可以实现静默安装。
更多相关文章
- Android(安卓)ViewPager的简单使用
- Android(安卓)应用安装位置
- android ndk 安装
- Android强制联网
- ios应用比android大,为什么iOS版APP安装文件比Android大几倍?
- Android(安卓)M 新的运行时权限开发者需要知道的一切
- Android(安卓)M 新的运行时权限开发者需要知道的一切
- 强烈推荐Android新手的入门学习策略之一,Android(安卓)Studio4使
- React Native接入现有Android原生工程并实现简单的RN与Android通