android代码控制安装apk
平时我们在使用商城的时候,下载完apk就可以自动的弹出安装的画面并且有的手机还会帮你检测apk的来源是否安全。
由于项目上有个需求是远程升级apk,所以需要在自己做的程序中代码控制安装apk。
网上查询了一番后有人给出了下述方法,用PackageInstaller帮助安装apk,这个其实是一个系统预安装的apk,就是我们平时用商城安装程序吊起的界面。
一番查询后网上给出了如下的解决方案:
File apk = new File(path);
Uri uri = FileProvider.getUriForFile(mContext, "com.yanfeng.poc.ota.fileProvider", apk);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setClassName("com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
然后发现会报如下的错误:
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.VIEW dat=content://com.yanfeng.poc.ota.fileProvider/apk/app-debug.apk typ=application/vnd.android.package-archive flg=0x10000001 cmp=com.android.packageinstaller/.PackageInstallerActivity } from ProcessRecord{a4b2c99 12176:com.yanfeng.poc.ota/u0a173} (pid=12176, uid=10173) not exported from uid 10046
一开始我以为是应用权限等级不够,不是系统应用无法拉起这个安装的界面,后来我在adb shell中用am start -n com.android.packageinstaller/.PackageInstallerActivity想要吊起界面依旧失败了,报错也类似有not exported from uid 10046这个字样,于是一番查询后发现uid其实是android资源是否能共享的一个标识符,如果在表单文件中对activity的exported设置为false那么不是同一个uid的进程不能吊起这个activity,也就是说.PackageInstallerActivity这个activity设置了exported为false,它不能用别的应用拉起它,只能是自己的activity跳转的时候拉起这个activity。于是我在adb shell中 敲入pm list package -f | grep install查看包名和apk的路径,我在安卓9.0的系统的板子上查询到了这个apk的路径如下
package:/system/priv-app/PackageInstaller/PackageInstaller.apk=com.android.packageinstaller
我们把这个apk拖动到android studio内可以查看它的表单文件,它有很多个activity,大部分都是exported为false
其中我找到了真正的我们应该吊起的activity
这个activity也是这个apk的默认启动activity。
也就是所如果我们能够将需要安装的apk的参数传递给这个activity并且吊起这个activity的界面我们就能够安装上apk。
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我们在我们需要用程序控制安装apk的manifest中加入如下3个权限,吊起activity的代码如下
File apk = new File(path);
Uri uri = FileProvider.getUriForFile(mContext, "com.yanfeng.poc.ota.fileProvider", apk);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setClassName("com.android.packageinstaller", "com.android.packageinstaller.InstallStart");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
然后程序就成功安装了