Android采用pm实现静默安装(降级安装)的解决方案

匿名 (未验证) 提交于 2019-12-02 22:56:40

最近在做一个apk分析器,里面可以解析系统中所有安装app的信息,并提供组内开发的apk文件下载、静默安装(包括降级安装),其中在降级安装中难度较大,在Android4.4与Android 8的解决方案不同,其他版本没有做测试。在此之前,打算聊聊adb的安装方式
目前暂时支持已经签过系统签名文件的apk,非系统签名暂时不支持。

adb安装apk常用命令如下:

adb install G:\demo.apk

即install后面接包在电脑上的路径,这里要确保已经通过adb连接到设备,常用以下命令连接,确保电脑与设备处于同一个局域网:

adb connect 设备ip

如果需要替换原来的应用,上面的安装命令是行不通的,需要加上“-r”,即替换原来的应用:

adb install -r G:\demo.apk

那如果是降级安装呢?再加“-d”:

adb install -r -d G:\demo.apk

这里的“r”指的是“replace”,替换原来的应用;“-d”指的是“downgrade”,降级安装
这不是成了吗?不对,这是通过adb命令,在Android应用中无法使用该命令,那么该如何解决呢?这里要引出另一个概念“pm”

“pm” 是指 “packageManager”,Android自带的PackageInstaller是通过pm来执行具体的安装工作,具体流程这里就不做分析了。我们来看如何直接通过pm来安装apk,首先进入shell模式,然后就可以使用pm命令:

adb shell pm install /data/data/demo.apk

这里的apk路径是在设备中的路径,同理如果要实现降级安装:

pm install -r -d /data/data/demo.apk

哈哈,是不是感觉在Android应用端实现该命令就很简单了?如下:

String cmd = "pm install -r -d /data/data/demo.apk" Runtime run = Runtime.getRuntime(); Process process = run.exec(cmd);

然后就failure了~~
该命令不是每一个应用都可以执行的,需要系统签名,将应用声明为系统应用。在Androidmanifest中配置:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="xxx.xxx.xxxx"        android:sharedUserId="android.uid.system">     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>

在run一次,ok,在Android4.4以及之前的版本没问题,但是在更高的版本,例如Android 7 就不行了,这里需要稍微修改一下:

pm install -r -d -i packageName --user 0  /data/data/demo.apk

这里的packageName是指调用这行命令的应用的包名

需要注意的是,runtime执行命令行会阻塞线程,因此需要在子线程中执行

那么,我们应该如何判断是否安装成功呢?很简单了,通过runtime执行返回的process就可以拿到输出的结果,完整代码如下:

   public void install(File apkFile) {         String cmd = "";         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {             cmd = "pm install -r -d " + apkFile.getAbsolutePath();         } else {             cmd = "pm install -r -d -i packageName --user 0 " + apkFile.getAbsolutePath();         }         Runtime runtime = Runtime.getRuntime();         try {             Process process = runtime.exec("");             InputStream errorInput = process.getErrorStream();             InputStream inputStream = process.getInputStream();             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));             String error = "";             String result = "";             String line = "";             while ((line = bufferedReader.readLine()) != null) {                 result += line;             }             bufferedReader = new BufferedReader(new InputStreamReader(errorInput));             while ((line = bufferedReader.readLine()) != null) {                 error += line;             }             if(result.equals("Success")){                 Log.i(TAG, "install: Success");             }else{                 Log.i(TAG, "install: error"+error);             }         } catch (IOException e) {             e.printStackTrace();         }     }

该方案需要获取系统权限,进行系统签名。当然,大家也可以在模拟器上试一试,拿到模拟器系统版本对应的源码,找到这3个文件

SignApk.jar 目录:/out/host/linux-x86/framework/signapk.jar
platform.x509.pem 目录:/build/target/product/security/platform.x509.pem
platform.pk8 目录:/build/target/product/security/platform.pk8

将这三个文件copy到同一个目录下,在该目录下执行:

java -jar SignApk.jar platform.x509.pem  platform.pk8 旧的apk.apk 生成的apk.apk  

即可以得到系统签名文件

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!