静默安装:
在某个触发点自动后台安装指定apk.没有安装界面.新软件自动安装,有旧版本的默默卸载,然后再安装,并且在不受系统设置中的第三方软件安装开关的限制.
自己跟踪记录的源码流程
Filemanager中点击apk包之后发送了一个intent出去
/* * uri = file:///storage/sdcard0/download/%E7%99%BE%E9%98%85.apk * mimeType = application/vnd.android.package-archive */ Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, mimeType); startActivity(intent); |
|
Android会去系统中的packagemanager中查询哪个apk能响应这个操作.
找到PackageInstaller这个apk.文件路劲位于packages\apps\PackageInstaller
<activity android:name=".PackageInstallerActivity" …..> <intent-filter>…… <data android:mimeType="application/vnd.android.package-archive" /> |
|
系统会启动这个Activity来进行安装操作
本文档只贴出具体安装的过程,舍弃ui操作,并加以简单说明
mPackageURI = intent.getData(); //获取安装包路劲 mPm = getPackageManager(); //获取packagemanager checkFileInvaild //检测给定的文件是否为一个apk.如果自己确定的东西,省略吧 final File sourceFile = new File(mPackageURI.getPath()); //把路劲转成file类型 PackageParser.Package mPkgInfo = PackageUtil.getPackageInfo(sourceFile); //解析apk getIconandTitle //根据mPkgInfo获取apk的icon和title.并存起来,对本题无用 if (!isInstallingUnknownAppsAllowed())//此处判断是否允许第三方软件安装.在设置里. initiateInstall(); //开始初始化安装 |
|
String pkgName = mPkgInfo.packageName; //得到包名 String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); if (oldName != null && oldName.length > 0 && oldName[0] != null) { pkgName = oldName[0]; mPkgInfo.setPackageName(pkgName); }//以上是检测是否存在该包名.但是其已经被改变成别的神马了.*我不知道是神马意思 mPm.getApplicationInfo(pkgName,PackageManager.GET_UNINSTALLED_PACKAGES); //检测是否有已经安装并未卸载的同名apk,有则弹出替代框(略过),无则安装 startInstallConfirm(); //弹出安装确认,点击ok newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); newIntent.setClass(this, InstallAppProgress.class); //把apk的info传入新的Activity安装 ….. |
|
mAppInfo = intent.getParcelableExtra(XXX); mPackageURI = intent.getData(); //从上面得到这些东西 String installerPackageName = getIntent().getStringExtra(xxxxPACKAGE_NAME); PackageInstallObserver observer = new PackageInstallObserver(); pm.installPackage(mPackageURI, observer, installFlags(0), installerPackageName); //安装过程就交个packagemanager去吧.我们不用管了. |
|
//如果你要等待此apk安装完了之后还要处理一些东东的话.看下面 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addDataScheme("package"); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_PACKAGE_REMOVED) {} else if (Intent.ACTION_PACKAGE_ADDED || Intent.ACTION_PACKAGE_REPLACED) {}} }, intentFilter); //上面主要就是监听三个事件并在receive中去处理. |
|
好了.回归主题.静默安装的关键代码已经出来了.只有一行
pm.installPackage(mPackageURI,observer, installFlags(0), installerPackageName);
看源码中该函数说明必须要加上android.Manifest.permission#INSTALL_PACKAGES才行,此权限只有system应用才能使用.所以此应用必须放入system/app下,才能保证其有效.方法就是反射
静默安装的第一种方法:
- package com.tnt.autoinstall;
-
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.InputStream;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
-
- import android.net.Uri;
- import android.os.Bundle;
- import android.app.Activity;
-
- public class MainActivity extends Activity {
- private Uri packageUri;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- packageUri = getPackageUri();
-
- install();
- }
-
- private void install()
- {
- try {
- Class<?> pmService;
- Class<?> activityTherad;
- Method method;
-
- activityTherad = Class.forName("android.app.ActivityThread");
- Class<?> paramTypes[] = getParamTypes(activityTherad , "getPackageManager");
- method = activityTherad.getMethod("getPackageManager", paramTypes);
- Object PackageManagerService = method.invoke(activityTherad);
-
- pmService = PackageManagerService.getClass();
-
- Class<?> paramTypes1[] = getParamTypes(pmService , "installPackage");
- method = pmService.getMethod("installPackage", paramTypes1);
- method.invoke(PackageManagerService , packageUri , null , 0 , null);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }catch (ClassNotFoundException e1) {
- e1.printStackTrace();
- }
- }
-
- private Class<?>[] getParamTypes(Class<?> cls, String mName) {
- Class<?> cs[] = null;
-
- Method[] mtd = cls.getMethods();
-
- for (int i = 0; i < mtd.length; i++) {
- if (!mtd[i].getName().equals(mName)) {
- continue;
- }
- cs = mtd[i].getParameterTypes();
- }
- return cs;
- }
-
- private Uri getPackageUri()
- {
- File file = new File("/storage/sdcard0/download/1.apk");
- return Uri.fromFile(file);
- }
- }
静默安装的第二种方法:
通过adb命令的方式来处理,代码如下,把上面的install函数替换下面代码
- private boolean install()
- {
- String[] args = {"pm", "install", "-r", packageUri.getPath()};
- String result = null;
- ProcessBuilder processBuilder = new ProcessBuilder(args);;
- Process process = null;
- InputStream errIs = null;
- InputStream inIs = null;
- try{
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int read = -1;
- process = processBuilder.start();
- errIs = process.getErrorStream();
- while((read = errIs.read()) != -1){
- baos.write(read);
- }
- baos.write('\n');
- inIs = process.getInputStream();
- while((read = inIs.read()) != -1){
- baos.write(read);
- }
- byte[] data = baos.toByteArray();
- result = new String(data);
- }catch(Exception e){
- e.printStackTrace();
- }finally{
- try{
- if(errIs != null){
- errIs.close();
- }
- if(inIs != null){
- inIs.close();
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- if(process != null){
- process.destroy();
- }
- }
-
- if(result != null && (result.endsWith("Success")||result.endsWith("Success\n")))
- {
- return true;
- }
- return false;
- }
下面看下卸载过程
同样的.需要增加一个权限android:name="android.permission.DELETE_PACKAGES".放入system/app中.
卸载方式一:adb shell pm方式
- private void uninstall2() {
- String[] args = { "pm", "uninstall", "com.popcap.pvzthird" };
- String result = null;
- ProcessBuilder processBuilder = new ProcessBuilder(args);
- ;
- Process process = null;
- InputStream errIs = null;
- InputStream inIs = null;
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int read = -1;
- process = processBuilder.start();
- errIs = process.getErrorStream();
- while ((read = errIs.read()) != -1) {
- baos.write(read);
- }
- baos.write('\n');
- inIs = process.getInputStream();
- while ((read = inIs.read()) != -1) {
- baos.write(read);
- }
- byte[] data = baos.toByteArray();
- result = new String(data);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- if (errIs != null) {
- errIs.close();
- }
- if (inIs != null) {
- inIs.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (process != null) {
- process.destroy();
- }
- }
- }
卸载方式二:反射调用系统函数
- Class<?> pmService;
- Class<?> activityTherad;
- Method method;
-
- activityTherad = Class.forName("android.app.ActivityThread");
- Class<?> paramTypes[] = getParamTypes(activityTherad,
- "getPackageManager");
- method = activityTherad.getMethod("getPackageManager", paramTypes);
- Object PackageManagerService = method.invoke(activityTherad);
-
- pmService = PackageManagerService.getClass();
-
- Class<?> paramTypes1[] = getParamTypes(pmService, "deletePackage");
- method = pmService.getMethod("deletePackage", paramTypes1);
- method.invoke(PackageManagerService, "com.popcap.pvzthird", null, 0);