Android 如何静默安装app

Android 要想静默安装app,必须是系统应用或者具有Root权限,否则根本不可能实现静默安装。

本文假设你的app是系统应用(有系统签名,或者放在系统/system/app 或 /system/priv-app分区),则可以进行以下安装:

1. 有提示的安装(所有第三方应用都可以)

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + apkFilePath), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
这是调用系统的AppInstaller,提示用户安装升级。

2. 静默安装:利用ProcessBuilder

    /**
     * install slient
     *
     * @param filePath
     * @return 0 means normal, 1 means file not exist, 2 means other exception error
     */
    public static int installSilent(String filePath) {
        File file = new File(filePath);
        if (filePath == null || filePath.length() == 0 || file == null || file.length() <= 0 || !file.exists() || !file.isFile()) {
            return 1;
        }

        String[] args = { "pm", "install", "-r", filePath };
        ProcessBuilder processBuilder = new ProcessBuilder(args);
        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder errorMsg = new StringBuilder();
        int result;
        try {
            process = processBuilder.start();
            successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
            errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String s;
            while ((s = successResult.readLine()) != null) {
                successMsg.append(s);
            }
            while ((s = errorResult.readLine()) != null) {
                errorMsg.append(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }

        // TODO should add memory is not enough here
        if (successMsg.toString().contains("Success") || successMsg.toString().contains("success")) {
            result = 0;
        } else {
            result = 2;
        }
        Log.d("test-test", "successMsg:" + successMsg + ", ErrorMsg:" + errorMsg);
        return result;
    }
3. 静默安装:利用Runtime.getRuntime().exec()

    private static final String TAG = "test-test";

    private static final int TIME_OUT = 60 * 1000;

    private static String[] SH_PATH = {
            "/system/bin/sh",
            "/system/xbin/sh",
            "/system/sbin/sh"
    };

    public static boolean executeInstallCommand(String filePath) {
        String command = “pm install -r ” + filePath;
        Process process = null;
        DataOutputStream os = null;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder errorMsg = new StringBuilder();
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        try {
            process = runWithEnv(getSuPath(), null);
            if (process == null) {
                return false;
            }

            successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
            errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes(command + "\n");
            os.writeBytes("echo \"rc:\" $?\n");
            os.writeBytes("exit\n");
            os.flush();

            String s;
            while ((s = successResult.readLine()) != null) {
                successMsg.append(s);
            }
            while ((s = errorResult.readLine()) != null) {
                errorMsg.append(s);
            }

            // Handle a requested timeout, or just use waitFor() otherwise.
            if (TIME_OUT > 0) {
                long finish = System.currentTimeMillis() + TIME_OUT;
                while (true) {
                    Thread.sleep(300);
                    if (!isProcessAlive(process)) {
                        break;
                    }

                    if (System.currentTimeMillis() > finish) {
                        Log.w(TAG, "Process doesn't seem to stop on it's own, assuming it's hanging");
                        // Note: 'finally' will call destroy(), but you might still see zombies.
                        return true;
                    }
                }
            } else {
                process.waitFor();
            }

            // In order to consider this a success, we require to things: a) a proper exit value, and ...
            if (process.exitValue() != 0) {
                return false;
            }

            return true;

        } catch (FileNotFoundException e) {
            Log.w(TAG, "Failed to run command, " + e.getMessage());
            return false;
        } catch (IOException e) {
            Log.w(TAG, "Failed to run command, " + e.getMessage());
            return false;
        } catch (InterruptedException e) {
            Log.w(TAG, "Failed to run command, " + e.getMessage());
            return false;
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            try {
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (process != null) {
                try {
                    // Yes, this really is the way to check if the process is still running.
                    process.exitValue();
                } catch (IllegalThreadStateException e) {
                    process.destroy();
                }
            }
        }
    }

    private static Process runWithEnv(String command, String[] customEnv) throws IOException {
        List<String> envList = new ArrayList<String>();
        Map<String, String> environment = System.getenv();
        if (environment != null) {
            for (Map.Entry<String, String> entry : environment.entrySet()) {
                envList.add(entry.getKey() + "=" + entry.getValue());
            }
        }

        if (customEnv != null) {
            for (String value : customEnv) {
                envList.add(value);
            }
        }

        String[] arrayEnv = null;
        if (envList.size() > 0) {
            arrayEnv = new String[envList.size()];
            for (int i = 0; i < envList.size(); i++) {
                arrayEnv[i] = envList.get(i);
            }
        }

        Process process = Runtime.getRuntime().exec(command, arrayEnv);
        return process;
    }

    /**
     * Check whether a process is still alive. We use this as a naive way to implement timeouts.
     */
    private static boolean isProcessAlive(Process p) {
        try {
            p.exitValue();
            return false;
        } catch (IllegalThreadStateException e) {
            return true;
        }
    }

    /** Get the SU file path if it exist */
    private static String getSuPath() {
        for (String p : SH_PATH) {
            File sh = new File(p);
            if (sh.exists()) {
                return p;
            }
        }
        return "su";
    }
4. 静默安装:利用反射调用API-PackageManager.installPackage()

    public static void installSilentWithReflection(Context context, String filePath) {
        try {
            PackageManager packageManager = context.getPackageManager();
            Method method = packageManager.getClass().getDeclaredMethod("installPackage",
                    new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class} );
            method.setAccessible(true);
            File apkFile = new File(filePath);
            Uri apkUri = Uri.fromFile(apkFile);

            method.invoke(packageManager, new Object[] {apkUri, new IPackageInstallObserver.Stub() {
                @Override
                public void packageInstalled(String pkgName, int resultCode) throws RemoteException {
                    Log.d(TAG, "packageInstalled = " + pkgName + "; resultCode = " + resultCode) ;
                }
            }, Integer.valueOf(2), "com.ali.babasecurity.yunos"});
            //PackageManager.INSTALL_REPLACE_EXISTING = 2;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
上面用到了反射调用,IPackageInstallObserver.class这个类在android sdk里面是没有的,您需要下载 android_dependency.jar放到你工程的libs目录,这个jar提供了与PackageManager反射调用相关的类的定义。

注意:静默安装还需要在你的AndroidManifest.xml中添加权限声明。该权限默认赋予系统应用,第三方应用即使声明了,也拿不到该权限!
<!-- 静默安装 -->
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />




评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值