pm install
會改變裝置安裝一個已經在裝置上的 APK,也就是 `adb install` 底層在做的事。
- 指令
- adb shell pm install
- 指令
- 套件(pm)
- 風險
- 會改變裝置
語法
pm install [-r] [-g] [-d] [-t] <path on device>旗標與參數
| token | 意義 |
|---|---|
| -r | 取代既有安裝,而不是直接失敗。 |
| -g | 安裝時就把所有執行期權限授予。 |
| -d | 允許降版。既有資料是新版寫的,舊版可能讀不動。 |
| -t | 允許標記為 testOnly 的 APK。 |
範例
pm install -r /data/local/tmp/app.apk從已經推到裝置上的檔案安裝或更新。
pm install -r -g /data/local/tmp/app.apk安裝並預先授予執行期權限,第一次開啟就不會跳對話框。
rm /data/local/tmp/app.apk大家都會忘記的那一步:不清掉的話,暫存的那份會留在手機上。
輸出怎麼讀
輸出範例
Success`Success`,或指出原因的 `Failure [INSTALL_FAILED_…]`。要搜的是括號裡那個 token。同一個失敗會以好幾種形狀抵達(`Failure [CODE]`、`Failure [CODE: 說明]`、`Error: CODE`,或一段 Java 例外堆疊),所以要在整段文字裡找 `INSTALL_FAILED_` 或 `INSTALL_PARSE_FAILED_`,而不是去比對某個句型。
輸出欄位
| 欄位 | 意義 |
|---|---|
| Success | 套件已安裝。 |
| INSTALL_FAILED_ALREADY_EXISTS | 已經安裝過了;用 `-r` 取代它。 |
| INSTALL_FAILED_VERSION_DOWNGRADE | 比已安裝的版本舊;用 `-d` 可以允許,但要留意資料的問題。 |
| INSTALL_FAILED_UPDATE_INCOMPATIBLE | 簽章憑證和已安裝的那份不同。 |
| INSTALL_FAILED_INSUFFICIENT_STORAGE | 空間不足。 |
| INSTALL_FAILED_MISSING_SPLIT | 這個 APK 是分割組合的一部分,要整組一起裝。 |
需要什麼權限
一條授權過的 `adb` 連線,再加上一件指令沒辦法替你檢查的事:手機得讀得到你指定的那個檔案。這就是為什麼 `/data/local/tmp/` 是慣用的暫存目錄,也是為什麼放在 shell 使用者摸不到的位置的 APK,會為了和裡面那個套件毫無關係的理由失敗。不需要 root 也不需要 `su`,正式版上本來也用不了 `adb root`。存取檢查之後還有兩道關卡,在怪 APK 之前值得先知道。裝置的套件驗證器(含 Play 保護機制)可以直接把安裝擋掉——這個套件的錯誤表裡那個 `disableVerifier` 補救方式就是為了它而存在。還有些安裝會在手機上跳提示,這也是 `unlockDevice` 會成為一種補救的原因:鎖著的螢幕可以把一次安裝拖到它自己放棄為止。
失敗訊息對照
| 訊息 | 意義 |
|---|---|
| Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE] | 已安裝的那份是用不同的金鑰簽的。沒有任何旗標救得了:這個套件的預檢把它列為唯一能事先知道的結果,而解法是先把已安裝的 app 連資料一起移除再裝。例外是帶著 v3 輪替血統、且能追溯到已安裝憑證的 APK,那會裝得毫無怨言。 |
| Failure [INSTALL_FAILED_VERSION_DOWNGRADE] | APK 的 versionCode 比手機上那個低。`-d` 允許它,而那個但書是實質的而不是客套的:手機上的資料是新版寫的,舊版可能讀不動,所以有時候得清掉那個 app 的資料才能讓它跑起來。 |
| Failure | 孤零零一個字、沒有括號也沒有代碼——舊版會印這個,什麼可搜的線索都沒留下。`recognizeInstallOutcome` 還是把它判成失敗而不是去猜,因為印出這個字的安裝什麼都沒裝進去。把兩條串流都收下來重跑一次,再去談原因。 |
| Exception occurred while executing 'install': java.lang.SecurityException: | 同一族失敗會用五種形狀抵達,這是其中一種。你要的 token 從來不在這一行——它如果在哪裡,是在底下那段堆疊追蹤裡——所以辨識器會在整段文字裡掃 `INSTALL_FAILED_` 或 `INSTALL_PARSE_FAILED_`,而不是去比對句型。 |
會改變什麼,以及怎麼回頭
安裝會取代原本那個 app。加上 `-d` 允許降版,而新版寫下的資料舊版可能讀不動,這個組合可能讓 app 一直壞著,直到你清掉它的資料。除此之外沒有破壞性的部分:回頭的路是把原本的版本裝回去,或解除安裝。
版本與廠商注意事項
- 路徑是裝置上的路徑。APK 得先在手機上,所以桌面版 `adb install` 會幫你先推上去。
- 對於 base 加 `split_config.*.apk` 的分割 app,這個指令幫不上忙:要用安裝工作階段(`pm install-create`)。
這個我們有 UI
APK Installer 會透過 USB 執行這個指令並解析回應——只要 Chromium 系瀏覽器,不必安裝 SDK,也不會上傳任何東西。
相關指令
和 pm install 會在同一次作業裡出現的指令。
| 指令 | 做什麼 |
|---|---|
| pm install-create | 開一個安裝工作階段,讓 base 與它的 split 作為一個不可分割的整體一起安裝。 |
| pm uninstall | 移除套件,或只針對一個 Android 使用者移除——這是不用 root 也能處理掉預載 app 的方法。 |
| pm path | 印出組成某個已安裝套件的 APK 檔絕對路徑。 |
| rm | 刪除裝置上的一個檔案,或一棵目錄樹。 |
其他套件(pm)指令
| 指令 | 做什麼 |
|---|---|
| pm list packages | 列出已安裝的套件,也能一次帶出 APK 路徑、uid、版本碼與安裝來源。 |
| pm disable-user | 在不移除的前提下,把套件對某個 Android 使用者關掉——比解除安裝安全,而且確定能還原。 |
| pm clear | 清除某個 app 的資料——在 Android 13 之後也可以只清快取。 |
| pm trim-caches | 要求系統一直丟掉快取檔案,直到剩下你指定的空間為止。 |
這些行為是在撰寫 Web ADB 工具背後的解析程式時,對照 AOSP、toybox 與核心原始碼查證的。真的會因 Android 版本或廠牌而異的地方,這一頁會直接說明,而不是給你一個在半數手機上都是錯的數字。