1. 程式人生 > >Android 實現Apk的後臺靜默安裝

Android 實現Apk的後臺靜默安裝

在Android上安裝其他Apk有兩種方式

1、啟動Android應用安裝器進行安裝

這種方式會彈出一個對話方塊使用者選擇是否安裝,實現程式碼如下,本文不做詳細介紹:

    /**
     * 安裝apk
     *
     * @param path apk路徑
     */
    public void update(String path) {
        Log.v("正確的安裝路徑", path);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
        startActivity(intent);
    }

2、通過pm命令安裝

通過這種方式可以實現Android apk的後臺靜默安裝。

首先對pm安裝做個簡單的介紹,在平常使用IntelliJ IDEA的過程中可以發現在安裝應用的過程中控制檯會出現如下輸出:

Waiting for device.
Target device: android-md_1008b-0123456789ABCDEF
Uploading file
	local path: E:\1.1\1.1\App\AndroidAssist\out\production\AppInstall\AppInstall.apk
	remote path: /data/local/tmp/com.example.AppInstall
Installing com.example.AppInstall
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example.AppInstall"
pkg: /data/local/tmp/com.example.AppInstall
Success
其中有一行 pm install -r "……",這就是執行的 pm 命令進行apk的安裝。

那麼問題來了,如何在Android執行shell命令,方式有兩種,一種是通過Runtime.exec(),另一種是ProcessBuilder。詳見:

終於,重點來了,Android通過pm命令實現apk的靜默安裝:

需要在Manifest.xml中申請安裝應用,以及其他需要的許可權:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
    <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
    <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/>
    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
應用安裝的許可權需要當前應用和系統Framwork有相同的簽名,在打包的時候必須進行簽名,否則無法實現應用的安裝。

對應用簽名時需要以下檔案platform.pk8 platform.x509.pem signapk.jar,將需要簽名的apk放置在同一目錄下然後在cmd視窗執行命令:

java -jar signapk.jar platform.x509.pem platform.pk8 input.apk output.apk

以AppInstall.apk為例:

java -jar signapk.jar platform.x509.pem platform.pk8 AppInstall.apk AppInstall_signed.apk

相關檔案的下載地址

實現apk安裝的關鍵程式碼如下:

/**
     * 安裝應用
     * @param apkAbsolutePath 安裝應用的路徑
     * @return 安裝結果的控制檯輸出
     */
    public String install(String apkAbsolutePath) {
        //初始化pm指令
        String[] args = {"pm", "install", "-r", apkAbsolutePath};
        String result = "";
        //程序生成器,將指令封裝成獨立的程序,進行呼叫
        ProcessBuilder processBuilder = new ProcessBuilder(args);
        //程序
        Process process = null;
        InputStream errIs = null;
        InputStream inIs = null;
        try {
            //位元組流,臨時儲存控制檯的輸出內容
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int read = -1;
            //執行安裝apk的pm指令
            process = processBuilder.start();
            //接收控制檯輸出的異常情況,輸入流
            errIs = process.getErrorStream();
            while ((read = errIs.read()) != -1) {
                baos.write(read);
            }
            baos.write("\r\n".getBytes());
            //正常輸出
            inIs = process.getInputStream();
            while ((read = inIs.read()) != -1) {
                baos.write(read);
            }
            byte[] data = baos.toByteArray();
            //將控制檯輸出轉化為字串返回
            result = new String(data);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//最後必須將所有輸入輸出流關閉
            try {
                if (errIs != null) {
                    errIs.close();
                }
                if (inIs != null) {
                    inIs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }
        return result;
    }
直接呼叫以上方法就能夠實現apk後臺靜默安裝。

demo的下載地址:

說明:

部分文章說需要在Manifest.xml中新增 android:sharedUserId="android.uid.system"以保證應用uid為system_uid,事實上是不需要的,另外如果添加了該部分的說明,會在靜態引用sdcard路徑時出現如下錯誤

Static storage paths aren’t available from AID_SYSTEM

詳見: