線上測試 Android App,代表手機放在別的地方。你透過網路連過去、安裝建置版本、在瀏覽器裡看畫面,再用 adb 拉 log,就像接著傳輸線一樣。做得好,它能取代一抽屜測試機帶給你的大部分東西;做得不好,它就只是一個多了幾道手續的慢速模擬器。
這篇指南把一個建置版本,從 APK 一路帶到三個 Android 版本上的當機 log。用的是我每週都在跑的指令,列出你會遇到的安裝錯誤,最後說明哪些情況下實體手機仍然是比較好的工具。
準備建置版本
從一個能用命令列安裝的建置版本開始。第一輪用 debug 版本就可以:
./gradlew assembleDebug ls app/build/outputs/apk/debug/
有兩項檢查能省下之後的時間。第一是 ABI。如果你的 App 有原生程式碼,確認 APK 裡有 arm64-v8a 的函式庫。以真實機型打造的手機是 arm64,而且不像你筆電上的 x86 模擬器映像檔,它們不會轉譯為其他架構編譯的程式碼。
unzip -l app/build/outputs/apk/debug/app-debug.apk | grep "lib/"
第二是 testOnly 旗標。在 Android Studio 按下 Run 時,IDE 會為 APK 加上 android:testOnly="true",而一般的 adb install 會拒絕它。用 assembleDebug 建置的版本則沒有這個旗標。如果你手上只有 IDE 建置的版本,用 adb install -t 安裝。
如果你的正式版產物是 App Bundle,用 bundletool 把它轉成給已連線手機用的 APK 集:
bundletool build-apks --bundle=app-release.aab --output=app.apks --connected-device bundletool install-apks --apks=app.apks
沒有加 --ks 時,bundletool 會用 debug 金鑰簽署。測試沒問題,但產出的檔案無法覆蓋安裝在以正式版金鑰簽署的版本上。
選三個 Android 版本,而不是一個
只用一支手機會掩蓋大部分相容性 bug,因為 Android 會以兩種方式改變行為。有些改變會影響新版本上的每個 App;有些則只在你調高 targetSdkVersion 時才會啟用。三個版本就能抓到這兩類的大部分:
- 你仍然支援的最舊版本,或盡量接近它的版本。2026 年,對大多數 App 來說,Android 12 是合理的下限。
- 在你自己的分析數據裡占比最高的版本,通常是 14 或 15。
- 最新的版本,16 或 17,強制無邊框(edge-to-edge)和預測返回這類依目標版本啟用的改變,會最先在這裡出現。
每兩個版本之間改變了什麼,完整列表很長。在不同 Android 版本上測試 App 有逐版本的檢查清單。
步驟 1:建立手機
在雲手機服務上,選一個 Android 版本和一款機型,大約一分鐘手機就準備好了。每台手機都依版本命名,例如 qa-12、qa-14 和 qa-16,這樣一週後的 log 和截圖依然看得懂。如果你要從 CI 用腳本處理,建立第一台裝置示範了透過 API 的同樣步驟。
挑使用者實際在用的機型。720p 面板的平價手機和 1440p 的旗艦機,會弄壞不同的版面,所以在三個版本之間混搭不同螢幕密度,同樣的時間能換到更多覆蓋率。
步驟 2:安裝建置版本
把 APK 放到手機上有三種方式:在瀏覽器控制台上傳、透過 REST API 傳送,或透過 ADB 中繼執行 adb install。App 指南說明了前兩種。如果用 adb,請依照 ADB 文件為你的 IP 位址開啟中繼,然後連線:
adb connect HOST:PORT adb -s HOST:PORT install -r app-debug.apk
安裝失敗幾乎都是以下五種之一,看錯誤字串就知道是哪一種:
| 錯誤 | 原因 | 解法 |
|---|---|---|
INSTALL_FAILED_NO_MATCHING_ABIS | 沒有符合手機 ABI 的原生函式庫 | 在 abiFilters 加入 arm64-v8a |
INSTALL_FAILED_TEST_ONLY | APK 是用 IDE 的 Run 按鈕建置的 | adb install -t,或用 Gradle 建置 |
INSTALL_FAILED_UPDATE_INCOMPATIBLE | 已經裝了一個用其他金鑰簽署的版本 | 先用 adb uninstall 移除舊版本 |
INSTALL_FAILED_DEPRECATED_SDK_VERSION | 在 Android 14 上目標版本低於 API 23,在 15 以上低於 24 | 調高 targetSdkVersion |
INSTALL_PARSE_FAILED_MANIFEST_MALFORMED | 在 12 以上,有 intent filter 的元件缺少 android:exported | 為每個這類元件宣告 exported |
步驟 3:跑一套可重複的冒煙測試
在每個版本上用同樣的方式跑同一套測試,這樣你看到的差異,才會是 Android 的差異,而不是你點擊方式的差異。我的這套涵蓋六件事:
- 冷啟動。
am start -W會以毫秒為單位印出TotalTime。跨版本比較,不要拿來和實體旗艦機比。 - 首次執行。安裝時不加
-g,讓每個執行階段權限提示都像新使用者看到的那樣出現。 - 切到背景再回來。按主畫面鍵,打開另外兩個 App,再回來。
- 程序被終止。App 在背景時,
am kill會像系統在記憶體不足時那樣結束程序。回到 App 時,必須還原畫面和狀態。 - 設定變更。深色模式、較大的字型、不同的顯示大小。
- 返回導覽。在每個頂層畫面用手勢返回。
指令如下,S 存放裝置位址:
S=HOST:PORT adb -s $S shell am force-stop com.example.app adb -s $S shell am start -W -n com.example.app/.MainActivity adb -s $S shell input keyevent KEYCODE_HOME adb -s $S shell am kill com.example.app adb -s $S shell cmd uimode night yes adb -s $S shell settings put system font_scale 1.3 adb -s $S shell wm density 560 adb -s $S shell wm density reset
下一輪之前,用 settings put system font_scale 1.0 還原字型大小、用 cmd uimode night no 關閉深色模式,或直接重置手機。
步驟 4:讀 log
每個情境開始前先清空緩衝區,然後只讀你自己的程序:
adb -s $S logcat -c adb -s $S shell am start -W -n com.example.app/.MainActivity adb -s $S logcat -d --pid=$(adb -s $S shell pidof -s com.example.app)
程序每次重新啟動,pid 都會改變,所以啟動時發生的當機不會出現在新的 pid 底下。改讀當機緩衝區,它會保留每個程序的 Java 與原生當機:
adb -s $S logcat -d -b crash adb -s $S logcat -d AndroidRuntime:E "*:S"
遇到 ANR 時,logcat 只會給你標題。adb bugreport report.zip 會收集那一刻的執行緒追蹤與系統狀態。要花一兩分鐘,而這就是要附在工單上的檔案。
把三份 log 並排比對。只在最新版本出現的警告,通常是依目標版本啟用的改變。三個版本都當機,就是你的程式碼的問題。
步驟 5:每輪之間重置
pm clear 會清除你 App 的資料,其他一切保持原樣:別的 App、你改過的設定、Google 帳號。想在不同測試套件之間做乾淨的比較,就把手機重置成全新狀態;pm clear 則留給同一套測試裡的快速重跑。
這套測試穩定之後,就該放進 CI。App 測試頁面示範了用 API 呼叫完成同樣的步驟。Instrumentation 測試就是一般的 adb 指令,所以在任何 adb 連得到的裝置上都能跑:
adb -s $S shell am instrument -w -e class com.example.LoginTest \ com.example.app.test/androidx.test.runner.AndroidJUnitRunner
線上測試的極限
老實說,資料中心裡的手機有些事告訴不了你:
- 相機畫質、自動對焦、真實的 GPS 漂移與生物辨識感測器。
- 圖形效能。虛擬化的 Android 透過轉譯或軟體驅動程式繪製畫面,所以影格時間和卡頓次數,無法套用到實體手機上。
- 耗電與過熱降頻。
- 廠商軟體。有些品牌的電池最佳化和自動啟動設定,會以原生 Android 不會的方式中止背景工作。
- 無線功能:NFC 支付、藍牙配對、電信業者功能。
留兩三支實體手機做這些檢查,大範圍的測試矩陣放到線上跑。
免費的入門方式
「免費線上真機測試」通常是指以下三種之一。你自己電腦上的 Android Emulator 完全免費,是改程式、跑起來那個循環的最佳場所。公有真機雲提供少量的實體手機免費額度,主要用於自動化測試。雲手機服務通常提供試用:Clousd 的前 30 分鐘免費,不需信用卡,足夠安裝一個建置版本並跑完第一輪冒煙測試,請見免費試用。


