文檔當前狀態:**alpha0.1**
* [x] 選題收集:2018/01/05
* [ ] 初稿整理:
* [ ] 補充校對:
* [ ] 入庫存檔:
---
[TOC]
# 
ADB,即 [Android Debug Bridge](https://developer.android.com/studio/command-line/adb.html),它是 Android 開發/測試人員不可替代的強大工具,也是 Android 設備玩家的好玩具。
持續更新中,歡迎提 PR 和 Issue 補充指正,覺得有用的可以將 [此 GitHub 倉庫](https://github.com/mzlogin/awesome-adb) Star 收藏備用。
**注:** 有部分命令的支持情況可能與 Android 系統版本及定制 ROM 的實現有關。
Other languages: [:gb: English](./README.en.md)
# 
## 基本用法
### 命令語法
adb 命令的基本語法如下:
```sh
adb [-d|-e|-s <serialNumber>] <command>
```
如果只有一個設備/模擬器連接時,可以省略掉 `[-d|-e|-s <serialNumber>]` 這一部分,直接使用 `adb <command>`。
### 為命令指定目標設備
如果有多個設備/模擬器連接,則需要為命令指定目標設備。
| 參數 | 含義 |
|---------------------|----------------------------------------------------|
| -d | 指定當前唯一通過 USB 連接的 Android 設備為命令目標 |
| -e | 指定當前唯一運行的模擬器為命令目標 |
| `-s <serialNumber>` | 指定相應 serialNumber 號的設備/模擬器為命令目標 |
在多個設備/模擬器連接的情況下較常用的是 `-s <serialNumber>` 參數,serialNumber 可以通過 `adb devices` 命令獲取。如:
```sh
$ adb devices
List of devices attached
cf264b8f device
emulator-5554 device
10.129.164.6:5555 device
```
輸出里的 `cf264b8f`、`emulator-5554` 和 `10.129.164.6:5555` 即為 serialNumber。
比如這時想指定 `cf264b8f` 這個設備來運行 adb 命令獲取屏幕分辨率:
```sh
adb -s cf264b8f shell wm size
```
又如想給 `10.129.164.6:5555` 這個設備安裝應用(*這種形式的 serialNumber 格式為 `<IP>:<Port>`,一般為無線連接的設備或 Genymotion 等第三方 Android 模擬器*):
```sh
adb -s 10.129.164.6:5555 install test.apk
```
**遇到多設備/模擬器的情況均使用這幾個參數為命令指定目標設備,下文中為簡化描述,不再重復。**
### 啟動/停止
啟動 adb server 命令:
```sh
adb start-server
```
(一般無需手動執行此命令,在運行 adb 命令時若發現 adb server 沒有啟動會自動調起。)
停止 adb server 命令:
```sh
adb kill-server
```
### 查看 adb 版本
命令:
```sh
adb version
```
示例輸出:
```sh
Android Debug Bridge version 1.0.36
Revision 8f855a3d9b35-android
```
### 以 root 權限運行 adbd
adb 的運行原理是 PC 端的 adb server 與手機端的守護進程 adbd 建立連接,然后 PC 端的 adb client 通過 adb server 轉發命令,adbd 接收命令后解析運行。
所以如果 adbd 以普通權限執行,有些需要 root 權限才能執行的命令無法直接用 `adb xxx` 執行。這時可以 `adb shell` 然后 `su` 后執行命令,也可以讓 adbd 以 root 權限執行,這個就能隨意執行高權限命令了。
命令:
```sh
adb root
```
正常輸出:
```sh
restarting adbd as root
```
現在再運行 `adb shell`,看看命令行提示符是不是變成 `#` 了?
有些手機 root 后也無法通過 `adb root` 命令讓 adbd 以 root 權限執行,比如三星的部分機型,會提示 `adbd cannot run as root in production builds`,此時可以先安裝 adbd Insecure,然后 `adb root` 試試。
相應地,如果要恢復 adbd 為非 root 權限的話,可以使用 `adb unroot` 命令。
### 指定 adb server 的網絡端口
命令:
```sh
adb -P <port> start-server
```
默認端口為 5037。
## 設備連接管理
### 查詢已連接設備/模擬器
命令:
```sh
adb devices
```
輸出示例:
```sh
List of devices attached
cf264b8f device
emulator-5554 device
10.129.164.6:5555 device
```
輸出格式為 `[serialNumber] [state]`,serialNumber 即我們常說的 SN,state 有如下幾種:
* `offline` —— 表示設備未連接成功或無響應。
* `device` —— 設備已連接。注意這個狀態并不能標識 Android 系統已經完全啟動和可操作,在設備啟動過程中設備實例就可連接到 adb,但啟動完畢后系統才處于可操作狀態。
* `no device` —— 沒有設備/模擬器連接。
以上輸出顯示當前已經連接了三臺設備/模擬器,`cf264b8f`、`emulator-5554` 和 `10.129.164.6:5555` 分別是它們的 SN。從 `emulator-5554` 這個名字可以看出它是一個 Android 模擬器,而 `10.129.164.6:5555` 這種形為 `<IP>:<Port>` 的 serialNumber 一般是無線連接的設備或 Genymotion 等第三方 Android 模擬器。
常見異常輸出:
1. 沒有設備/模擬器連接成功。
```sh
List of devices attached
```
2. 設備/模擬器未連接到 adb 或無響應。
```sh
List of devices attached
cf264b8f offline
```
### USB 連接
通過 USB 連接來正常使用 adb 需要保證幾點:
1. 硬件狀態正常。
包括 Android 設備處于正常開機狀態,USB 連接線和各種接口完好。
2. Android 設備的開發者選項和 USB 調試模式已開啟。
可以到「設置」-「開發者選項」-「Android 調試」查看。
如果在設置里找不到開發者選項,那需要通過一個彩蛋來讓它顯示出來:在「設置」-「關于手機」連續點擊「版本號」7 次。
3. 設備驅動狀態正常。
這一點貌似在 Linux 和 Mac OS X 下不用操心,在 Windows 下有可能遇到需要安裝驅動的情況,確認這一點可以右鍵「計算機」-「屬性」,到「設備管理器」里查看相關設備上是否有黃色感嘆號或問號,如果沒有就說明驅動狀態已經好了。否則可以下載一個手機助手類程序來安裝驅動先。
4. 通過 USB 線連接好電腦和設備后確認狀態。
```sh
adb devices
```
如果能看到
```sh
xxxxxx device
```
說明連接成功。
### 無線連接(需要借助 USB 線)
除了可以通過 USB 連接設備與電腦來使用 adb,也可以通過無線連接——雖然連接過程中也有需要使用 USB 的步驟,但是連接成功之后你的設備就可以在一定范圍內擺脫 USB 連接線的限制啦!
操作步驟:
1. 將 Android 設備與要運行 adb 的電腦連接到同一個局域網,比如連到同一個 WiFi。
2. 將設備與電腦通過 USB 線連接。
應確保連接成功(可運行 `adb devices` 看是否能列出該設備)。
3. 讓設備在 5555 端口監聽 TCP/IP 連接:
```sh
adb tcpip 5555
```
4. 斷開 USB 連接。
5. 找到設備的 IP 地址。
一般能在「設置」-「關于手機」-「狀態信息」-「IP地址」找到,也可以使用下文里 [查看設備信息 - IP 地址][1] 一節里的方法用 adb 命令來查看。
6. 通過 IP 地址連接設備。
```sh
adb connect <device-ip-address>
```
這里的 `<device-ip-address>` 就是上一步中找到的設備 IP 地址。
7. 確認連接狀態。
```sh
adb devices
```
如果能看到
```sh
<device-ip-address>:5555 device
```
說明連接成功。
如果連接不了,請確認 Android 設備與電腦是連接到了同一個 WiFi,然后再次執行 `adb connect <device-ip-address>` 那一步;
如果還是不行的話,通過 `adb kill-server` 重新啟動 adb 然后從頭再來一次試試。
**斷開無線連接**
命令:
```sh
adb disconnect <device-ip-address>
```
### 無線連接(無需借助 USB 線)
**注:需要 root 權限。**
上一節「無線連接(需要借助 USB 線)」是官方文檔里介紹的方法,需要借助于 USB 數據線來實現無線連接。
既然我們想要實現無線連接,那能不能所有步驟下來都是無線的呢?答案是能的。
1. 在 Android 設備上安裝一個終端模擬器。
已經安裝過的設備可以跳過此步。我使用的終端模擬器下載地址是:[Terminal Emulator for Android Downloads](https://jackpal.github.io/Android-Terminal-Emulator/)
2. 將 Android 設備與要運行 adb 的電腦連接到同一個局域網,比如連到同一個 WiFi。
3. 打開 Android 設備上的終端模擬器,在里面依次運行命令:
```sh
su
setprop service.adb.tcp.port 5555
```
4. 找到 Android 設備的 IP 地址。
一般能在「設置」-「關于手機」-「狀態信息」-「IP地址」找到,也可以使用下文里 [查看設備信息 - IP 地址][1] 一節里的方法用 adb 命令來查看。
5. 在電腦上通過 adb 和 IP 地址連接 Android 設備。
```sh
adb connect <device-ip-address>
```
這里的 `<device-ip-address>` 就是上一步中找到的設備 IP 地址。
如果能看到 `connected to <device-ip-address>:5555` 這樣的輸出則表示連接成功。
*節注一:*
有的設備,比如小米 5S + MIUI 8.0 + Android 6.0.1 MXB48T,可能在第 5 步之前需要重啟 adbd 服務,在設備的終端模擬器上運行:
```sh
restart adbd
```
如果 restart 無效,嘗試以下命令:
```sh
stop adbd
start adbd
```
## 應用管理
### 查看應用列表
查看應用列表的基本命令格式是
```sh
adb shell pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]
```
即在 `adb shell pm list packages` 的基礎上可以加一些參數進行過濾查看不同的列表,支持的過濾參數如下:
| 參數 | 顯示列表 |
|------------|----------------------------|
| 無 | 所有應用 |
| -f | 顯示應用關聯的 apk 文件 |
| -d | 只顯示 disabled 的應用 |
| -e | 只顯示 enabled 的應用 |
| -s | 只顯示系統應用 |
| -3 | 只顯示第三方應用 |
| -i | 顯示應用的 installer |
| -u | 包含已卸載應用 |
| `<FILTER>` | 包名包含 `<FILTER>` 字符串 |
#### 所有應用
命令:
```sh
adb shell pm list packages
```
輸出示例:
```sh
package:com.android.smoketest
package:com.example.android.livecubes
package:com.android.providers.telephony
package:com.google.android.googlequicksearchbox
package:com.android.providers.calendar
package:com.android.providers.media
package:com.android.protips
package:com.android.documentsui
package:com.android.gallery
package:com.android.externalstorage
...
// other packages here
...
```
#### 系統應用
命令:
```sh
adb shell pm list packages -s
```
#### 第三方應用
命令:
```sh
adb shell pm list packages -3
```
#### 包名包含某字符串的應用
比如要查看包名包含字符串 `mazhuang` 的應用列表,命令:
```sh
adb shell pm list packages mazhuang
```
當然也可以使用 grep 來過濾:
```sh
adb shell pm list packages | grep mazhuang
```
### 安裝 APK
命令格式:
```sh
adb install [-lrtsdg] <path_to_apk>
```
參數:
`adb install` 后面可以跟一些可選參數來控制安裝 APK 的行為,可用參數及含義如下:
| 參數 | 含義 |
|------|-----------------------------------------------------------------------------------|
| -l | 將應用安裝到保護目錄 /mnt/asec |
| -r | 允許覆蓋安裝 |
| -t | 允許安裝 AndroidManifest.xml 里 application 指定 `android:testOnly="true"` 的應用 |
| -s | 將應用安裝到 sdcard |
| -d | 允許降級覆蓋安裝 |
| -g | 授予所有運行時權限 |
運行命令后如果見到類似如下輸出(狀態為 `Success`)代表安裝成功:
```sh
[100%] /data/local/tmp/1.apk
pkg: /data/local/tmp/1.apk
Success
```
上面是當前最新版 v1.0.36 的 adb 的輸出,會顯示 push apk 文件到手機的進度百分比。
使用舊版本 adb 的輸出則是這樣的:
```sh
12040 KB/s (22205609 bytes in 1.801s)
pkg: /data/local/tmp/SogouInput_android_v8.3_sweb.apk
Success
```
而如果狀態為 `Failure` 則表示安裝失敗,比如:
```sh
[100%] /data/local/tmp/map-20160831.apk
pkg: /data/local/tmp/map-20160831.apk
Failure [INSTALL_FAILED_ALREADY_EXISTS]
```
常見安裝失敗輸出代碼、含義及可能的解決辦法如下:
| 輸出 | 含義 | 解決辦法 |
|---------------------------------------------------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------------|
| INSTALL\_FAILED\_ALREADY\_EXISTS | 應用已經存在,或卸載了但沒卸載干凈 | `adb install` 時使用 `-r` 參數,或者先 `adb uninstall <packagename>` 再安裝 |
| INSTALL\_FAILED\_INVALID\_APK | 無效的 APK 文件 | |
| INSTALL\_FAILED\_INVALID\_URI | 無效的 APK 文件名 | 確保 APK 文件名里無中文 |
| INSTALL\_FAILED\_INSUFFICIENT\_STORAGE | 空間不足 | 清理空間 |
| INSTALL\_FAILED\_DUPLICATE\_PACKAGE | 已經存在同名程序 | |
| INSTALL\_FAILED\_NO\_SHARED\_USER | 請求的共享用戶不存在 | |
| INSTALL\_FAILED\_UPDATE\_INCOMPATIBLE | 以前安裝過同名應用,但卸載時數據沒有移除;或者已安裝該應用,但簽名不一致 | 先 `adb uninstall <packagename>` 再安裝 |
| INSTALL\_FAILED\_SHARED\_USER\_INCOMPATIBLE | 請求的共享用戶存在但簽名不一致 | |
| INSTALL\_FAILED\_MISSING\_SHARED\_LIBRARY | 安裝包使用了設備上不可用的共享庫 | |
| INSTALL\_FAILED\_REPLACE\_COULDNT\_DELETE | 替換時無法刪除 | |
| INSTALL\_FAILED\_DEXOPT | dex 優化驗證失敗或空間不足 | |
| INSTALL\_FAILED\_OLDER\_SDK | 設備系統版本低于應用要求 | |
| INSTALL\_FAILED\_CONFLICTING\_PROVIDER | 設備里已經存在與應用里同名的 content provider | |
| INSTALL\_FAILED\_NEWER\_SDK | 設備系統版本高于應用要求 | |
| INSTALL\_FAILED\_TEST\_ONLY | 應用是 test-only 的,但安裝時沒有指定 `-t` 參數 | |
| INSTALL\_FAILED\_CPU\_ABI\_INCOMPATIBLE | 包含不兼容設備 CPU 應用程序二進制接口的 native code | |
| INSTALL\_FAILED\_MISSING\_FEATURE | 應用使用了設備不可用的功能 | |
| INSTALL\_FAILED\_CONTAINER\_ERROR | 1. sdcard 訪問失敗;<br />2. 應用簽名與 ROM 簽名一致,被當作內置應用。 | 1. 確認 sdcard 可用,或者安裝到內置存儲;<br />2. 打包時不與 ROM 使用相同簽名。 |
| INSTALL\_FAILED\_INVALID\_INSTALL\_LOCATION | 1. 不能安裝到指定位置;<br />2. 應用簽名與 ROM 簽名一致,被當作內置應用。 | 1. 切換安裝位置,添加或刪除 `-s` 參數;<br />2. 打包時不與 ROM 使用相同簽名。 |
| INSTALL\_FAILED\_MEDIA\_UNAVAILABLE | 安裝位置不可用 | 一般為 sdcard,確認 sdcard 可用或安裝到內置存儲 |
| INSTALL\_FAILED\_VERIFICATION\_TIMEOUT | 驗證安裝包超時 | |
| INSTALL\_FAILED\_VERIFICATION\_FAILURE | 驗證安裝包失敗 | |
| INSTALL\_FAILED\_PACKAGE\_CHANGED | 應用與調用程序期望的不一致 | |
| INSTALL\_FAILED\_UID\_CHANGED | 以前安裝過該應用,與本次分配的 UID 不一致 | 清除以前安裝過的殘留文件 |
| INSTALL\_FAILED\_VERSION\_DOWNGRADE | 已經安裝了該應用更高版本 | 使用 `-d` 參數 |
| INSTALL\_FAILED\_PERMISSION\_MODEL\_DOWNGRADE | 已安裝 target SDK 支持運行時權限的同名應用,要安裝的版本不支持運行時權限 | |
| INSTALL\_PARSE\_FAILED\_NOT\_APK | 指定路徑不是文件,或不是以 `.apk` 結尾 | |
| INSTALL\_PARSE\_FAILED\_BAD\_MANIFEST | 無法解析的 AndroidManifest.xml 文件 | |
| INSTALL\_PARSE\_FAILED\_UNEXPECTED\_EXCEPTION | 解析器遇到異常 | |
| INSTALL\_PARSE\_FAILED\_NO\_CERTIFICATES | 安裝包沒有簽名 | |
| INSTALL\_PARSE\_FAILED\_INCONSISTENT\_CERTIFICATES | 已安裝該應用,且簽名與 APK 文件不一致 | 先卸載設備上的該應用,再安裝 |
| INSTALL\_PARSE\_FAILED\_CERTIFICATE\_ENCODING | 解析 APK 文件時遇到 `CertificateEncodingException` | |
| INSTALL\_PARSE\_FAILED\_BAD\_PACKAGE\_NAME | manifest 文件里沒有或者使用了無效的包名 | |
| INSTALL\_PARSE\_FAILED\_BAD\_SHARED\_USER\_ID | manifest 文件里指定了無效的共享用戶 ID | |
| INSTALL\_PARSE\_FAILED\_MANIFEST\_MALFORMED | 解析 manifest 文件時遇到結構性錯誤 | |
| INSTALL\_PARSE\_FAILED\_MANIFEST\_EMPTY | 在 manifest 文件里找不到找可操作標簽(instrumentation 或 application) | |
| INSTALL\_FAILED\_INTERNAL\_ERROR | 因系統問題安裝失敗 | |
| INSTALL\_FAILED\_USER\_RESTRICTED | 用戶被限制安裝應用 | |
| INSTALL\_FAILED\_DUPLICATE\_PERMISSION | 應用嘗試定義一個已經存在的權限名稱 | |
| INSTALL\_FAILED\_NO\_MATCHING\_ABIS | 應用包含設備的應用程序二進制接口不支持的 native code | |
| INSTALL\_CANCELED\_BY\_USER | 應用安裝需要在設備上確認,但未操作設備或點了取消 | 在設備上同意安裝 |
| INSTALL\_FAILED\_ACWF\_INCOMPATIBLE | 應用程序與設備不兼容 | |
| does not contain AndroidManifest.xml | 無效的 APK 文件 | |
| is not a valid zip file | 無效的 APK 文件 | |
| Offline | 設備未連接成功 | 先將設備與 adb 連接成功 |
| unauthorized | 設備未授權允許調試 | |
| error: device not found | 沒有連接成功的設備 | 先將設備與 adb 連接成功 |
| protocol failure | 設備已斷開連接 | 先將設備與 adb 連接成功 |
| Unknown option: -s | Android 2.2 以下不支持安裝到 sdcard | 不使用 `-s` 參數 |
| No space left on device | 空間不足 | 清理空間 |
| Permission denied ... sdcard ... | sdcard 不可用 | |
| signatures do not match the previously installed version; ignoring! | 已安裝該應用且簽名不一致 | 先卸載設備上的該應用,再安裝 |
參考:[PackageManager.java](https://github.com/android/platform_frameworks_base/blob/master/core%2Fjava%2Fandroid%2Fcontent%2Fpm%2FPackageManager.java)
*`adb install` 內部原理簡介*
`adb install` 實際是分三步完成:
1. push apk 文件到 /data/local/tmp。
2. 調用 pm install 安裝。
3. 刪除 /data/local/tmp 下的對應 apk 文件。
所以,必要的時候也可以根據這個步驟,手動分步執行安裝過程。
### 卸載應用
命令:
```sh
adb uninstall [-k] <packagename>
```
`<packagename>` 表示應用的包名,`-k` 參數可選,表示卸載應用但保留數據和緩存目錄。
命令示例:
```sh
adb uninstall com.qihoo360.mobilesafe
```
表示卸載 360 手機衛士。
### 清除應用數據與緩存
命令:
```sh
adb shell pm clear <packagename>
```
`<packagename>` 表示應用名包,這條命令的效果相當于在設置里的應用信息界面點擊了「清除緩存」和「清除數據」。
命令示例:
```sh
adb shell pm clear com.qihoo360.mobilesafe
```
表示清除 360 手機衛士的數據和緩存。
### 查看前臺 Activity
命令:
```sh
adb shell dumpsys activity activities | grep mFocusedActivity
```
輸出示例:
```sh
mFocusedActivity: ActivityRecord{8079d7e u0 com.cyanogenmod.trebuchet/com.android.launcher3.Launcher t42}
```
其中的 `com.cyanogenmod.trebuchet/com.android.launcher3.Launcher` 就是當前處于前臺的 Activity。
### 查看正在運行的 Services
命令:
```sh
adb shell dumpsys activity services [<packagename>]
```
`<packagename>` 參數不是必須的,指定 `<packagename>` 表示查看與某個包名相關的 Services,不指定表示查看所有 Services。
`<packagename>` 不一定要給出完整的包名,比如運行 `adb shell dumpsys activity services org.mazhuang`,那么包名 `org.mazhuang.demo1`、`org.mazhuang.demo2` 和 `org.mazhuang123` 等相關的 Services 都會列出來。
### 查看應用詳細信息
命令:
```sh
adb shell dumpsys package <packagename>
```
輸出中包含很多信息,包括 Activity Resolver Table、Registered ContentProviders、包名、userId、安裝后的文件資源代碼等路徑、版本信息、權限信息和授予狀態、簽名版本信息等。
`<packagename>` 表示應用包名。
輸出示例:
```sh
Activity Resolver Table:
Non-Data Actions:
android.intent.action.MAIN:
5b4cba8 org.mazhuang.guanggoo/.SplashActivity filter 5ec9dcc
Action: "android.intent.action.MAIN"
Category: "android.intent.category.LAUNCHER"
AutoVerify=false
Registered ContentProviders:
org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider:
Provider{7a3c394 org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider}
ContentProvider Authorities:
[org.mazhuang.guanggoo.fileProvider]:
Provider{7a3c394 org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider}
applicationInfo=ApplicationInfo{7754242 org.mazhuang.guanggoo}
Key Set Manager:
[org.mazhuang.guanggoo]
Signing KeySets: 501
Packages:
Package [org.mazhuang.guanggoo] (c1d7f):
userId=10394
pkg=Package{55f714c org.mazhuang.guanggoo}
codePath=/data/app/org.mazhuang.guanggoo-2
resourcePath=/data/app/org.mazhuang.guanggoo-2
legacyNativeLibraryDir=/data/app/org.mazhuang.guanggoo-2/lib
primaryCpuAbi=null
secondaryCpuAbi=null
versionCode=74 minSdk=15 targetSdk=25
versionName=1.1.74
splits=[base]
apkSigningVersion=2
applicationInfo=ApplicationInfo{7754242 org.mazhuang.guanggoo}
flags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
privateFlags=[ RESIZEABLE_ACTIVITIES ]
dataDir=/data/user/0/org.mazhuang.guanggoo
supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]
timeStamp=2017-10-22 23:50:53
firstInstallTime=2017-10-22 23:50:25
lastUpdateTime=2017-10-22 23:50:55
installerPackageName=com.miui.packageinstaller
signatures=PackageSignatures{af09595 [53c7caa2]}
installPermissionsFixed=true installStatus=1
pkgFlags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
requested permissions:
android.permission.READ_PHONE_STATE
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.READ_LOGS
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE
install permissions:
android.permission.INTERNET: granted=true
android.permission.ACCESS_NETWORK_STATE: granted=true
android.permission.ACCESS_WIFI_STATE: granted=true
User 0: ceDataInode=1155675 installed=true hidden=false suspended=false stopped=true notLaunched=false enabled=0
gids=[3003]
runtime permissions:
android.permission.READ_EXTERNAL_STORAGE: granted=true
android.permission.READ_PHONE_STATE: granted=true
android.permission.WRITE_EXTERNAL_STORAGE: granted=true
User 999: ceDataInode=0 installed=false hidden=false suspended=false stopped=true notLaunched=true enabled=0
gids=[3003]
runtime permissions:
Dexopt state:
[org.mazhuang.guanggoo]
Instruction Set: arm64
path: /data/app/org.mazhuang.guanggoo-2/base.apk
status: /data/app/org.mazhuang.guanggoo-2/oat/arm64/base.odex [compilation_filter=speed-profile, status=kOatUpToDa
te]
```
## 與應用交互
主要是使用 `am <command>` 命令,常用的 `<command>` 如下:
| command | 用途 |
|-----------------------------------|---------------------------------|
| `start [options] <INTENT>` | 啟動 `<INTENT>` 指定的 Activity |
| `startservice [options] <INTENT>` | 啟動 `<INTENT>` 指定的 Service |
| `broadcast [options] <INTENT>` | 發送 `<INTENT>` 指定的廣播 |
| `force-stop <packagename>` | 停止 `<packagename>` 相關的進程 |
`<INTENT>` 參數很靈活,和寫 Android 程序時代碼里的 Intent 相對應。
用于決定 intent 對象的選項如下:
| 參數 | 含義 |
|------------------|---------------------------------------------------------------------------------------------|
| `-a <ACTION>` | 指定 action,比如 `android.intent.action.VIEW` |
| `-c <CATEGORY>` | 指定 category,比如 `android.intent.category.APP_CONTACTS` |
| `-n <COMPONENT>` | 指定完整 component 名,用于明確指定啟動哪個 Activity,如 `com.example.app/.ExampleActivity` |
`<INTENT>` 里還能帶數據,就像寫代碼時的 Bundle 一樣:
| 參數 | 含義 |
|---------------------------------------------------------------|----------------------------------------|
| `--esn <EXTRA_KEY>` | null 值(只有 key 名) |
| `-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE>` | string 值 |
| `--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>` | boolean 值 |
| `--ei <EXTRA_KEY> <EXTRA_INT_VALUE>` | integer 值 |
| `--el <EXTRA_KEY> <EXTRA_LONG_VALUE>` | long 值 |
| `--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE>` | float 值 |
| `--eu <EXTRA_KEY> <EXTRA_URI_VALUE>` | URI |
| `--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>` | component name |
| `--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]` | integer 數組 |
| `--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]` | long 數組 |
### 調起 Activity
命令格式:
```sh
adb shell am start [options] <INTENT>
```
例如:
```sh
adb shell am start -n com.tencent.mm/.ui.LauncherUI
```
表示調起微信主界面。
```sh
adb shell am start -n org.mazhuang.boottimemeasure/.MainActivity --es "toast" "hello, world"
```
表示調起 `org.mazhuang.boottimemeasure/.MainActivity` 并傳給它 string 數據鍵值對 `toast - hello, world`。
### 調起 Service
命令格式:
```sh
adb shell am startservice [options] <INTENT>
```
例如:
```sh
adb shell am startservice -n com.tencent.mm/.plugin.accountsync.model.AccountAuthenticatorService
```
表示調起微信的某 Service。
### 發送廣播
命令格式:
```sh
adb shell am broadcast [options] <INTENT>
```
可以向所有組件廣播,也可以只向指定組件廣播。
例如,向所有組件廣播 `BOOT_COMPLETED`:
```sh
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED
```
又例如,只向 `org.mazhuang.boottimemeasure/.BootCompletedReceiver` 廣播 `BOOT_COMPLETED`:
```sh
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n org.mazhuang.boottimemeasure/.BootCompletedReceiver
```
這類用法在測試的時候很實用,比如某個廣播的場景很難制造,可以考慮通過這種方式來發送廣播。
既能發送系統預定義的廣播,也能發送自定義廣播。如下是部分系統預定義廣播及正常觸發時機:
| action | 觸發時機 |
|-------------------------------------------------|-----------------------------------------------|
| android.net.conn.CONNECTIVITY_CHANGE | 網絡連接發生變化 |
| android.intent.action.SCREEN_ON | 屏幕點亮 |
| android.intent.action.SCREEN_OFF | 屏幕熄滅 |
| android.intent.action.BATTERY_LOW | 電量低,會彈出電量低提示框 |
| android.intent.action.BATTERY_OKAY | 電量恢復了 |
| android.intent.action.BOOT_COMPLETED | 設備啟動完畢 |
| android.intent.action.DEVICE_STORAGE_LOW | 存儲空間過低 |
| android.intent.action.DEVICE_STORAGE_OK | 存儲空間恢復 |
| android.intent.action.PACKAGE_ADDED | 安裝了新的應用 |
| android.net.wifi.STATE_CHANGE | WiFi 連接狀態發生變化 |
| android.net.wifi.WIFI_STATE_CHANGED | WiFi 狀態變為啟用/關閉/正在啟動/正在關閉/未知 |
| android.intent.action.BATTERY_CHANGED | 電池電量發生變化 |
| android.intent.action.INPUT_METHOD_CHANGED | 系統輸入法發生變化 |
| android.intent.action.ACTION_POWER_CONNECTED | 外部電源連接 |
| android.intent.action.ACTION_POWER_DISCONNECTED | 外部電源斷開連接 |
| android.intent.action.DREAMING_STARTED | 系統開始休眠 |
| android.intent.action.DREAMING_STOPPED | 系統停止休眠 |
| android.intent.action.WALLPAPER_CHANGED | 壁紙發生變化 |
| android.intent.action.HEADSET_PLUG | 插入耳機 |
| android.intent.action.MEDIA_UNMOUNTED | 卸載外部介質 |
| android.intent.action.MEDIA_MOUNTED | 掛載外部介質 |
| android.os.action.POWER_SAVE_MODE_CHANGED | 省電模式開啟 |
*(以上廣播均可使用 adb 觸發)*
### 強制停止應用
命令:
```sh
adb shell am force-stop <packagename>
```
命令示例:
```sh
adb shell am force-stop com.qihoo360.mobilesafe
```
表示停止 360 安全衛士的一切進程與服務。
## 文件管理
### 復制設備里的文件到電腦
命令:
```sh
adb pull <設備里的文件路徑> [電腦上的目錄]
```
其中 `電腦上的目錄` 參數可以省略,默認復制到當前目錄。
例:
```sh
adb pull /sdcard/sr.mp4 ~/tmp/
```
*小技巧:*設備上的文件路徑可能需要 root 權限才能訪問,如果你的設備已經 root 過,可以先使用 `adb shell` 和 `su` 命令在 adb shell 里獲取 root 權限后,先 `cp /path/on/device /sdcard/filename` 將文件復制到 sdcard,然后 `adb pull /sdcard/filename /path/on/pc`。
### 復制電腦里的文件到設備
命令:
```sh
adb push <電腦上的文件路徑> <設備里的目錄>
```
例:
```sh
adb push ~/sr.mp4 /sdcard/
```
*小技巧:*設備上的文件路徑普通權限可能無法直接寫入,如果你的設備已經 root 過,可以先 `adb push /path/on/pc /sdcard/filename`,然后 `adb shell` 和 `su` 在 adb shell 里獲取 root 權限后,`cp /sdcard/filename /path/on/device`。
## 模擬按鍵/輸入
在 `adb shell` 里有個很實用的命令叫 `input`,通過它可以做一些有趣的事情。
`input` 命令的完整 help 信息如下:
```sh
Usage: input [<source>] <command> [<arg>...]
The sources are:
mouse
keyboard
joystick
touchnavigation
touchpad
trackball
stylus
dpad
gesture
touchscreen
gamepad
The commands and default sources are:
text <string> (Default: touchscreen)
keyevent [--longpress] <key code number or name> ... (Default: keyboard)
tap <x> <y> (Default: touchscreen)
swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
press (Default: trackball)
roll <dx> <dy> (Default: trackball)
```
比如使用 `adb shell input keyevent <keycode>` 命令,不同的 keycode 能實現不同的功能,完整的 keycode 列表詳見 [KeyEvent](https://developer.android.com/reference/android/view/KeyEvent.html),摘引部分我覺得有意思的如下:
| keycode | 含義 |
|---------|--------------------------------|
| 3 | HOME 鍵 |
| 4 | 返回鍵 |
| 5 | 打開撥號應用 |
| 6 | 掛斷電話 |
| 24 | 增加音量 |
| 25 | 降低音量 |
| 26 | 電源鍵 |
| 27 | 拍照(需要在相機應用里) |
| 64 | 打開瀏覽器 |
| 82 | 菜單鍵 |
| 85 | 播放/暫停 |
| 86 | 停止播放 |
| 87 | 播放下一首 |
| 88 | 播放上一首 |
| 122 | 移動光標到行首或列表頂部 |
| 123 | 移動光標到行末或列表底部 |
| 126 | 恢復播放 |
| 127 | 暫停播放 |
| 164 | 靜音 |
| 176 | 打開系統設置 |
| 187 | 切換應用 |
| 207 | 打開聯系人 |
| 208 | 打開日歷 |
| 209 | 打開音樂 |
| 210 | 打開計算器 |
| 220 | 降低屏幕亮度 |
| 221 | 提高屏幕亮度 |
| 223 | 系統休眠 |
| 224 | 點亮屏幕 |
| 231 | 打開語音助手 |
| 276 | 如果沒有 wakelock 則讓系統休眠 |
下面是 `input` 命令的一些用法舉例。
### 電源鍵
命令:
```sh
adb shell input keyevent 26
```
執行效果相當于按電源鍵。
### 菜單鍵
命令:
```sh
adb shell input keyevent 82
```
### HOME 鍵
命令:
```sh
adb shell input keyevent 3
```
### 返回鍵
命令:
```sh
adb shell input keyevent 4
```
### 音量控制
增加音量:
```sh
adb shell input keyevent 24
```
降低音量:
```sh
adb shell input keyevent 25
```
靜音:
```sh
adb shell input keyevent 164
```
### 媒體控制
播放/暫停:
```sh
adb shell input keyevent 85
```
停止播放:
```sh
adb shell input keyevent 86
```
播放下一首:
```sh
adb shell input keyevent 87
```
播放上一首:
```sh
adb shell input keyevent 88
```
恢復播放:
```sh
adb shell input keyevent 126
```
暫停播放:
```sh
adb shell input keyevent 127
```
### 點亮/熄滅屏幕
可以通過上文講述過的模擬電源鍵來切換點亮和熄滅屏幕,但如果明確地想要點亮或者熄滅屏幕,那可以使用如下方法。
點亮屏幕:
```sh
adb shell input keyevent 224
```
熄滅屏幕:
```sh
adb shell input keyevent 223
```
### 滑動解鎖
如果鎖屏沒有密碼,是通過滑動手勢解鎖,那么可以通過 `input swipe` 來解鎖。
命令(參數以機型 Nexus 5,向上滑動手勢解鎖舉例):
```sh
adb shell input swipe 300 1000 300 500
```
參數 `300 1000 300 500` 分別表示`起始點x坐標 起始點y坐標 結束點x坐標 結束點y坐標`。
### 輸入文本
在焦點處于某文本框時,可以通過 `input` 命令來輸入文本。
命令:
```sh
adb shell input text hello
```
現在 `hello` 出現在文本框了。
## 查看日志
Android 系統的日志分為兩部分,底層的 Linux 內核日志輸出到 /proc/kmsg,Android 的日志輸出到 /dev/log。
### Android 日志
命令格式:
```sh
[adb] logcat [<option>] ... [<filter-spec>] ...
```
常用用法列舉如下:
#### 按級別過濾日志
Android 的日志分為如下幾個優先級(priority):
* V —— Verbose(最低,輸出得最多)
* D —— Debug
* I —— Info
* W —— Warning
* E —— Error
* F —— Fatal
* S —— Silent(最高,啥也不輸出)
按某級別過濾日志則會將該級別及以上的日志輸出。
比如,命令:
```sh
adb logcat *:W
```
會將 Warning、Error、Fatal 和 Silent 日志輸出。
(**注:** 在 macOS 下需要給 `*:W` 這樣以 `*` 作為 tag 的參數加雙引號,如 `adb logcat "*:W"`,不然會報錯 `no matches found: *:W`。)
#### 按 tag 和級別過濾日志
`<filter-spec>` 可以由多個 `<tag>[:priority]` 組成。
比如,命令:
```sh
adb logcat ActivityManager:I MyApp:D *:S
```
表示輸出 tag `ActivityManager` 的 Info 以上級別日志,輸出 tag `MyApp` 的 Debug 以上級別日志,及其它 tag 的 Silent 級別日志(即屏蔽其它 tag 日志)。
#### 日志格式
可以用 `adb logcat -v <format>` 選項指定日志輸出格式。
日志支持按以下幾種 `<format>`:
* brief
默認格式。格式為:
```sh
<priority>/<tag>(<pid>): <message>
```
示例:
```sh
D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0
```
* process
格式為:
```sh
<priority>(<pid>) <message>
```
示例:
```sh
D( 1785) Disconnected process message: 10, size: 0 (HeadsetStateMachine)
```
* tag
格式為:
```sh
<priority>/<tag>: <message>
```
示例:
```sh
D/HeadsetStateMachine: Disconnected process message: 10, size: 0
```
* raw
格式為:
```sh
<message>
```
示例:
```sh
Disconnected process message: 10, size: 0
```
* time
格式為:
```sh
<datetime> <priority>/<tag>(<pid>): <message>
```
示例:
```sh
08-28 22:39:39.974 D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0
```
* threadtime
格式為:
```sh
<datetime> <pid> <tid> <priority> <tag>: <message>
```
示例:
```sh
08-28 22:39:39.974 1785 1832 D HeadsetStateMachine: Disconnected process message: 10, size: 0
```
* long
格式為:
```sh
[ <datetime> <pid>:<tid> <priority>/<tag> ]
<message>
```
示例:
```sh
[ 08-28 22:39:39.974 1785: 1832 D/HeadsetStateMachine ]
Disconnected process message: 10, size: 0
```
指定格式可與上面的過濾同時使用。比如:
```sh
adb logcat -v long ActivityManager:I *:S
```
#### 清空日志
```sh
adb logcat -c
```
### 內核日志
命令:
```sh
adb shell dmesg
```
輸出示例:
```sh
<6>[14201.684016] PM: noirq resume of devices complete after 0.982 msecs
<6>[14201.685525] PM: early resume of devices complete after 0.838 msecs
<6>[14201.753642] PM: resume of devices complete after 68.106 msecs
<4>[14201.755954] Restarting tasks ... done.
<6>[14201.771229] PM: suspend exit 2016-08-28 13:31:32.679217193 UTC
<6>[14201.872373] PM: suspend entry 2016-08-28 13:31:32.780363596 UTC
<6>[14201.872498] PM: Syncing filesystems ... done.
```
中括號里的 `[14201.684016]` 代表內核開始啟動后的時間,單位為秒。
通過內核日志我們可以做一些事情,比如衡量內核啟動時間,在系統啟動完畢后的內核日志里找到 `Freeing init memory` 那一行前面的時間就是。
## 查看設備信息
### 型號
命令:
```sh
adb shell getprop ro.product.model
```
輸出示例:
```sh
Nexus 5
```
### 電池狀況
命令:
```sh
adb shell dumpsys battery
```
輸入示例:
```sh
Current Battery Service state:
AC powered: false
USB powered: true
Wireless powered: false
status: 2
health: 2
present: true
level: 44
scale: 100
voltage: 3872
temperature: 280
technology: Li-poly
```
其中 `scale` 代表最大電量,`level` 代表當前電量。上面的輸出表示還剩下 44% 的電量。
### 屏幕分辨率
命令:
```sh
adb shell wm size
```
輸出示例:
```sh
Physical size: 1080x1920
```
該設備屏幕分辨率為 1080px * 1920px。
如果使用命令修改過,那輸出可能是:
```sh
Physical size: 1080x1920
Override size: 480x1024
```
表明設備的屏幕分辨率原本是 1080px * 1920px,當前被修改為 480px * 1024px。
### 屏幕密度
命令:
```sh
adb shell wm density
```
輸出示例:
```sh
Physical density: 420
```
該設備屏幕密度為 420dpi。
如果使用命令修改過,那輸出可能是:
```sh
Physical density: 480
Override density: 160
```
表明設備的屏幕密度原來是 480dpi,當前被修改為 160dpi。
### 顯示屏參數
命令:
```sh
adb shell dumpsys window displays
```
輸出示例:
```sh
WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
Display: mDisplayId=0
init=1080x1920 420dpi cur=1080x1920 app=1080x1794 rng=1080x1017-1810x1731
deferred=false layoutNeeded=false
```
其中 `mDisplayId` 為 顯示屏編號,`init` 是初始分辨率和屏幕密度,`app` 的高度比 `init` 里的要小,表示屏幕底部有虛擬按鍵,高度為 1920 - 1794 = 126px 合 42dp。
### android\_id
命令:
```sh
adb shell settings get secure android_id
```
輸出示例:
```sh
51b6be48bac8c569
```
### IMEI
在 Android 4.4 及以下版本可通過如下命令獲取 IMEI:
```sh
adb shell dumpsys iphonesubinfo
```
輸出示例:
```sh
Phone Subscriber Info:
Phone Type = GSM
Device ID = 860955027785041
```
其中的 `Device ID` 就是 IMEI。
而在 Android 5.0 及以上版本里這個命令輸出為空,得通過其它方式獲取了(需要 root 權限):
```sh
adb shell
su
service call iphonesubinfo 1
```
輸出示例:
```sh
Result: Parcel(
0x00000000: 00000000 0000000f 00360038 00390030 '........8.6.0.9.'
0x00000010: 00350035 00320030 00370037 00350038 '5.5.0.2.7.7.8.5.'
0x00000020: 00340030 00000031 '0.4.1... ')
```
把里面的有效內容提取出來就是 IMEI 了,比如這里的是 `860955027785041`。
參考:[adb shell dumpsys iphonesubinfo not working since Android 5.0 Lollipop](http://stackoverflow.com/questions/27002663/adb-shell-dumpsys-iphonesubinfo-not-working-since-android-5-0-lollipop)
### Android 系統版本
命令:
```sh
adb shell getprop ro.build.version.release
```
輸出示例:
```sh
5.0.2
```
### IP 地址
每次想知道設備的 IP 地址的時候都得「設置」-「關于手機」-「狀態信息」-「IP地址」很煩對不對?通過 adb 可以方便地查看。
命令:
```sh
adb shell ifconfig | grep Mask
```
輸出示例:
```sh
inet addr:10.130.245.230 Mask:255.255.255.252
inet addr:127.0.0.1 Mask:255.0.0.0
```
那么 `10.130.245.230` 就是設備 IP 地址。
在有的設備上這個命令沒有輸出,如果設備連著 WiFi,可以使用如下命令來查看局域網 IP:
```sh
adb shell ifconfig wlan0
```
輸出示例:
```sh
wlan0: ip 10.129.160.99 mask 255.255.240.0 flags [up broadcast running multicast]
```
或
```sh
wlan0 Link encap:UNSPEC
inet addr:10.129.168.57 Bcast:10.129.175.255 Mask:255.255.240.0
inet6 addr: fe80::66cc:2eff:fe68:b6b6/64 Scope: Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:496520 errors:0 dropped:0 overruns:0 frame:0
TX packets:68215 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3000
RX bytes:116266821 TX bytes:8311736
```
如果以上命令仍然不能得到期望的信息,那可以試試以下命令(部分系統版本里可用):
```sh
adb shell netcfg
```
輸出示例:
```sh
wlan0 UP 10.129.160.99/20 0x00001043 f8:a9:d0:17:42:4d
lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00
p2p0 UP 0.0.0.0/0 0x00001003 fa:a9:d0:17:42:4d
sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00
rmnet0 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet1 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet3 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet2 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet4 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet6 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet5 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rmnet7 DOWN 0.0.0.0/0 0x00000000 00:00:00:00:00:00
rev_rmnet3 DOWN 0.0.0.0/0 0x00001002 4e:b7:e4:2e:17:58
rev_rmnet2 DOWN 0.0.0.0/0 0x00001002 4e:f0:c8:bf:7a:cf
rev_rmnet4 DOWN 0.0.0.0/0 0x00001002 a6:c0:3b:6b:c4:1f
rev_rmnet6 DOWN 0.0.0.0/0 0x00001002 66:bb:5d:64:2e:e9
rev_rmnet5 DOWN 0.0.0.0/0 0x00001002 0e:1b:eb:b9:23:a0
rev_rmnet7 DOWN 0.0.0.0/0 0x00001002 7a:d9:f6:81:40:5a
rev_rmnet8 DOWN 0.0.0.0/0 0x00001002 4e:e2:a9:bb:d0:1b
rev_rmnet0 DOWN 0.0.0.0/0 0x00001002 fe:65:d0:ca:82:a9
rev_rmnet1 DOWN 0.0.0.0/0 0x00001002 da:d8:e8:4f:2e:fe
```
可以看到網絡連接名稱、啟用狀態、IP 地址和 Mac 地址等信息。
### Mac 地址
命令:
```sh
adb shell cat /sys/class/net/wlan0/address
```
輸出示例:
```sh
f8:a9:d0:17:42:4d
```
這查看的是局域網 Mac 地址,移動網絡或其它連接的信息可以通過前面的小節「IP 地址」里提到的 `adb shell netcfg` 命令來查看。
### CPU 信息
命令:
```sh
adb shell cat /proc/cpuinfo
```
輸出示例:
```sh
Processor : ARMv7 Processor rev 0 (v7l)
processor : 0
BogoMIPS : 38.40
processor : 1
BogoMIPS : 38.40
processor : 2
BogoMIPS : 38.40
processor : 3
BogoMIPS : 38.40
Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0x2
CPU part : 0x06f
CPU revision : 0
Hardware : Qualcomm MSM 8974 HAMMERHEAD (Flattened Device Tree)
Revision : 000b
Serial : 0000000000000000
```
這是 Nexus 5 的 CPU 信息,我們從輸出里可以看到使用的硬件是 `Qualcomm MSM 8974`,processor 的編號是 0 到 3,所以它是四核的,采用的架構是 `ARMv7 Processor rev 0 (v71)`。
### 內存信息
命令:
```sh
adb shell cat /proc/meminfo
```
輸出示例:
```sh
MemTotal: 1027424 kB
MemFree: 486564 kB
Buffers: 15224 kB
Cached: 72464 kB
SwapCached: 24152 kB
Active: 110572 kB
Inactive: 259060 kB
Active(anon): 79176 kB
Inactive(anon): 207736 kB
Active(file): 31396 kB
Inactive(file): 51324 kB
Unevictable: 3948 kB
Mlocked: 0 kB
HighTotal: 409600 kB
HighFree: 132612 kB
LowTotal: 617824 kB
LowFree: 353952 kB
SwapTotal: 262140 kB
SwapFree: 207572 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 265324 kB
Mapped: 47072 kB
Shmem: 1020 kB
Slab: 57372 kB
SReclaimable: 7692 kB
SUnreclaim: 49680 kB
KernelStack: 4512 kB
PageTables: 5912 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 775852 kB
Committed_AS: 13520632 kB
VmallocTotal: 385024 kB
VmallocUsed: 61004 kB
VmallocChunk: 209668 kB
```
其中,`MemTotal` 就是設備的總內存,`MemFree` 是當前空閑內存。
### 更多硬件與系統屬性
設備的更多硬件與系統屬性可以通過如下命令查看:
```sh
adb shell cat /system/build.prop
```
這會輸出很多信息,包括前面幾個小節提到的「型號」和「Android 系統版本」等。
輸出里還包括一些其它有用的信息,它們也可通過 `adb shell getprop <屬性名>` 命令單獨查看,列舉一部分屬性如下:
| 屬性名 | 含義 |
|---------------------------------|-------------------------------|
| ro.build.version.sdk | SDK 版本 |
| ro.build.version.release | Android 系統版本 |
| ro.build.version.security_patch | Android 安全補丁程序級別 |
| ro.product.model | 型號 |
| ro.product.brand | 品牌 |
| ro.product.name | 設備名 |
| ro.product.board | 處理器型號 |
| ro.product.cpu.abilist | CPU 支持的 abi 列表[*節注一*] |
| persist.sys.isUsbOtgEnabled | 是否支持 OTG |
| dalvik.vm.heapsize | 每個應用程序的內存上限 |
| ro.sf.lcd_density | 屏幕密度 |
*節注一:*
一些小廠定制的 ROM 可能修改過 CPU 支持的 abi 列表的屬性名,如果用 `ro.product.cpu.abilist` 屬性名查找不到,可以這樣試試:
```sh
adb shell cat /system/build.prop | grep ro.product.cpu.abi
```
示例輸出:
```sh
ro.product.cpu.abi=armeabi-v7a
ro.product.cpu.abi2=armeabi
```
## 修改設置
**注:** 修改設置之后,運行恢復命令有可能顯示仍然不太正常,可以運行 `adb reboot` 重啟設備,或手動重啟。
修改設置的原理主要是通過 settings 命令修改 /data/data/com.android.providers.settings/databases/settings.db 里存放的設置值。
### 分辨率
命令:
```sh
adb shell wm size 480x1024
```
表示將分辨率修改為 480px * 1024px。
恢復原分辨率命令:
```sh
adb shell wm size reset
```
### 屏幕密度
命令:
```sh
adb shell wm density 160
```
表示將屏幕密度修改為 160dpi。
恢復原屏幕密度命令:
```sh
adb shell wm density reset
```
### 顯示區域
命令:
```sh
adb shell wm overscan 0,0,0,200
```
四個數字分別表示距離左、上、右、下邊緣的留白像素,以上命令表示將屏幕底部 200px 留白。
恢復原顯示區域命令:
```sh
adb shell wm overscan reset
```
### 關閉 USB 調試模式
命令:
```sh
adb shell settings put global adb_enabled 0
```
恢復:
用命令恢復不了了,畢竟關閉了 USB 調試 adb 就連接不上 Android 設備了。
去設備上手動恢復吧:「設置」-「開發者選項」-「Android 調試」。
### 狀態欄和導航欄的顯示隱藏
本節所說的相關設置對應 Cyanogenmod 里的「擴展桌面」。
命令:
```sh
adb shell settings put global policy_control <key-values>
```
`<key-values>` 可由如下幾種鍵及其對應的值組成,格式為 `<key1>=<value1>:<key2>=<value2>`。
| key | 含義 |
|-----------------------|------------|
| immersive.full | 同時隱藏 |
| immersive.status | 隱藏狀態欄 |
| immersive.navigation | 隱藏導航欄 |
| immersive.preconfirms | ? |
這些鍵對應的值可則如下值用逗號組合:
| value | 含義 |
|----------------|--------------|
| `apps` | 所有應用 |
| `*` | 所有界面 |
| `packagename` | 指定應用 |
| `-packagename` | 排除指定應用 |
例如:
```sh
adb shell settings put global policy_control immersive.full=*
```
表示設置在所有界面下都同時隱藏狀態欄和導航欄。
```sh
adb shell settings put global policy_control immersive.status=com.package1,com.package2:immersive.navigation=apps,-com.package3
```
表示設置在包名為 `com.package1` 和 `com.package2` 的應用里隱藏狀態欄,在除了包名為 `com.package3` 的所有應用里隱藏導航欄。
## 實用功能
### 屏幕截圖
截圖保存到電腦:
```sh
adb exec-out screencap -p > sc.png
```
如果 adb 版本較老,無法使用 `exec-out` 命令,這時候建議更新 adb 版本。無法更新的話可以使用以下麻煩點的辦法:
先截圖保存到設備里:
```sh
adb shell screencap -p /sdcard/sc.png
```
然后將 png 文件導出到電腦:
```sh
adb pull /sdcard/sc.png
```
可以使用 `adb shell screencap -h` 查看 `screencap` 命令的幫助信息,下面是兩個有意義的參數及含義:
| 參數 | 含義 |
|---------------|--------------------------------------------|
| -p | 指定保存文件為 png 格式 |
| -d display-id | 指定截圖的顯示屏編號(有多顯示屏的情況下) |
實測如果指定文件名以 `.png` 結尾時可以省略 -p 參數;否則需要使用 -p 參數。如果不指定文件名,截圖文件的內容將直接輸出到 stdout。
另外一種一行命令截圖并保存到電腦的方法:
*Linux 和 Windows*
```sh
adb shell screencap -p | sed "s/\r$//" > sc.png
```
*Mac OS X*
```sh
adb shell screencap -p | gsed "s/\r$//" > sc.png
```
這個方法需要用到 gnu sed 命令,在 Linux 下直接就有,在 Windows 下 Git 安裝目錄的 bin 文件夾下也有。如果確實找不到該命令,可以下載 [sed for Windows](http://gnuwin32.sourceforge.net/packages/sed.htm) 并將 sed.exe 所在文件夾添加到 PATH 環境變量里。
而在 Mac 下使用系統自帶的 sed 命令會報錯:
```sh
sed: RE error: illegal byte sequence
```
需要安裝 gnu-sed,然后使用 gsed 命令:
```sh
brew install gnu-sed
```
### 錄制屏幕
錄制屏幕以 mp4 格式保存到 /sdcard:
```sh
adb shell screenrecord /sdcard/filename.mp4
```
需要停止時按 <kbd>Ctrl-C</kbd>,默認錄制時間和最長錄制時間都是 180 秒。
如果需要導出到電腦:
```sh
adb pull /sdcard/filename.mp4
```
可以使用 `adb shell screenrecord --help` 查看 `screenrecord` 命令的幫助信息,下面是常見參數及含義:
| 參數 | 含義 |
|---------------------|-------------------------------------------------|
| --size WIDTHxHEIGHT | 視頻的尺寸,比如 `1280x720`,默認是屏幕分辨率。 |
| --bit-rate RATE | 視頻的比特率,默認是 4Mbps。 |
| --time-limit TIME | 錄制時長,單位秒。 |
| --verbose | 輸出更多信息。 |
### 重新掛載 system 分區為可寫
**注:需要 root 權限。**
/system 分區默認掛載為只讀,但有些操作比如給 Android 系統添加命令、刪除自帶應用等需要對 /system 進行寫操作,所以需要重新掛載它為可讀寫。
步驟:
1. 進入 shell 并切換到 root 用戶權限。
命令:
```sh
adb shell
su
```
2. 查看當前分區掛載情況。
命令:
```sh
mount
```
輸出示例:
```sh
rootfs / rootfs ro,relatime 0 0
tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,mode=755 0 0
devpts /dev/pts devpts rw,seclabel,relatime,mode=600 0 0
proc /proc proc rw,relatime 0 0
sysfs /sys sysfs rw,seclabel,relatime 0 0
selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
none /var tmpfs rw,seclabel,relatime,mode=770,gid=1000 0 0
none /acct cgroup rw,relatime,cpuacct 0 0
none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0
none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
tmpfs /mnt/asec tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0
tmpfs /mnt/obb tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0
none /dev/memcg cgroup rw,relatime,memory 0 0
none /dev/cpuctl cgroup rw,relatime,cpu 0 0
none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0
none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
none /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
/dev/block/platform/msm_sdcc.1/by-name/userdata /data ext4 rw,seclabel,nosuid,nodev,relatime,noauto_da_alloc,data=ordered 0 0
/dev/block/platform/msm_sdcc.1/by-name/cache /cache ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0
/dev/block/platform/msm_sdcc.1/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0
/dev/block/platform/msm_sdcc.1/by-name/modem /firmware vfat ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,gid=1000,fmask=0337,dmask=0227,codepage=cp437,iocharset=iso8859-1,shortname=lower,errors=remount-ro 0 0
/dev/fuse /mnt/shell/emulated fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
/dev/fuse /mnt/shell/emulated/0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
```
找到其中我們關注的帶 /system 的那一行:
```sh
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
```
3. 重新掛載。
命令:
```sh
mount -o remount,rw -t yaffs2 /dev/block/platform/msm_sdcc.1/by-name/system /system
```
這里的 `/dev/block/platform/msm_sdcc.1/by-name/system` 就是我們從上一步的輸出里得到的文件路徑。
如果輸出沒有提示錯誤的話,操作就成功了,可以對 /system 下的文件為所欲為了。
### 查看連接過的 WiFi 密碼
**注:需要 root 權限。**
命令:
```sh
adb shell
su
cat /data/misc/wifi/*.conf
```
輸出示例:
```sh
network={
ssid="TP-LINK_9DFC"
scan_ssid=1
psk="123456789"
key_mgmt=WPA-PSK
group=CCMP TKIP
auth_alg=OPEN
sim_num=1
priority=13893
}
network={
ssid="TP-LINK_F11E"
psk="987654321"
key_mgmt=WPA-PSK
sim_num=1
priority=17293
}
```
`ssid` 即為我們在 WLAN 設置里看到的名稱,`psk` 為密碼,`key_mgmt` 為安全加密方式。
### 設置系統日期和時間
**注:需要 root 權限。**
命令:
```sh
adb shell
su
date -s 20160823.131500
```
表示將系統日期和時間更改為 2016 年 08 月 23 日 13 點 15 分 00 秒。
### 重啟手機
命令:
```sh
adb reboot
```
### 檢測設備是否已 root
命令:
```sh
adb shell
su
```
此時命令行提示符是 `$` 則表示沒有 root 權限,是 `#` 則表示已 root。
### 使用 Monkey 進行壓力測試
Monkey 可以生成偽隨機用戶事件來模擬單擊、觸摸、手勢等操作,可以對正在開發中的程序進行隨機壓力測試。
簡單用法:
```sh
adb shell monkey -p <packagename> -v 500
```
表示向 `<packagename>` 指定的應用程序發送 500 個偽隨機事件。
Monkey 的詳細用法參考 [官方文檔](https://developer.android.com/studio/test/monkey.html)。
### 開啟/關閉 WiFi
**注:需要 root 權限。**
有時需要控制設備的 WiFi 狀態,可以用以下指令完成。
開啟 WiFi:
```sh
adb root
adb shell svc wifi enable
```
關閉 WiFi:
```sh
adb root
adb shell svc wifi disable
```
若執行成功,輸出為空;若未取得 root 權限執行此命令,將執行失敗,輸出 `Killed`。
## 刷機相關命令
### 重啟到 Recovery 模式
命令:
```sh
adb reboot recovery
```
### 從 Recovery 重啟到 Android
命令:
```sh
adb reboot
```
### 重啟到 Fastboot 模式
命令:
```sh
adb reboot bootloader
```
### 通過 sideload 更新系統
如果我們下載了 Android 設備對應的系統更新包到電腦上,那么也可以通過 adb 來完成更新。
以 Recovery 模式下更新為例:
1. 重啟到 Recovery 模式。
命令:
```sh
adb reboot recovery
```
2. 在設備的 Recovery 界面上操作進入 `Apply update`-`Apply from ADB`。
注:不同的 Recovery 菜單可能與此有差異,有的是一級菜單就有 `Apply update from ADB`。
3. 通過 adb 上傳和更新系統。
命令:
```sh
adb sideload <path-to-update.zip>
```
## 安全相關命令
### 啟用/禁用 SELinux
啟用 SELinux
```sh
adb root
adb shell setenforce 1
```
禁用 SELinux
```sh
adb root
adb shell setenforce 0
```
### 啟用/禁用 dm_verity
啟用 dm_verity
```sh
adb root
adb enable-verity
```
禁用 dm_verity
```sh
adb root
adb disable-verity
```
## 更多 adb shell 命令
Android 系統是基于 Linux 內核的,所以 Linux 里的很多命令在 Android 里也有相同或類似的實現,在 `adb shell` 里可以調用。本文檔前面的部分內容已經用到了 `adb shell` 命令。
### 查看進程
命令:
```sh
adb shell ps
```
輸出示例:
```sh
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 8904 788 ffffffff 00000000 S /init
root 2 0 0 0 ffffffff 00000000 S kthreadd
...
u0_a71 7779 5926 1538748 48896 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
u0_a58 7963 5926 1561916 59568 ffffffff 00000000 S org.mazhuang.boottimemeasure
...
shell 8750 217 10640 740 00000000 b6f28340 R ps
```
各列含義:
| 列名 | 含義 |
|------|-----------|
| USER | 所屬用戶 |
| PID | 進程 ID |
| PPID | 父進程 ID |
| NAME | 進程名 |
### 查看實時資源占用情況
命令:
```sh
adb shell top
```
輸出示例:
```sh
User 0%, System 6%, IOW 0%, IRQ 0%
User 3 + Nice 0 + Sys 21 + Idle 280 + IOW 0 + IRQ 0 + SIRQ 3 = 307
PID PR CPU% S #THR VSS RSS PCY UID Name
8763 0 3% R 1 10640K 1064K fg shell top
131 0 3% S 1 0K 0K fg root dhd_dpc
6144 0 0% S 115 1682004K 115916K fg system system_server
132 0 0% S 1 0K 0K fg root dhd_rxf
1731 0 0% S 6 20288K 788K fg root /system/bin/mpdecision
217 0 0% S 6 18008K 356K fg shell /sbin/adbd
...
7779 2 0% S 19 1538748K 48896K bg u0_a71 com.sohu.inputmethod.sogou:classic
7963 0 0% S 18 1561916K 59568K fg u0_a58 org.mazhuang.boottimemeasure
...
```
各列含義:
| 列名 | 含義 |
|------|------------------------------------------------------------|
| PID | 進程 ID |
| PR | 優先級 |
| CPU% | 當前瞬間占用 CPU 百分比 |
| S | 進程狀態(R=運行,S=睡眠,T=跟蹤/停止,Z=僵尸進程) |
| #THR | 線程數 |
| VSS | Virtual Set Size 虛擬耗用內存(包含共享庫占用的內存) |
| RSS | Resident Set Size 實際使用物理內存(包含共享庫占用的內存) |
| PCY | 調度策略優先級,SP_BACKGROUND/SPFOREGROUND |
| UID | 進程所有者的用戶 ID |
| NAME | 進程名 |
`top` 命令還支持一些命令行參數,詳細用法如下:
```sh
Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]
-m num 最多顯示多少個進程
-n num 刷新多少次后退出
-d num 刷新時間間隔(單位秒,默認值 5)
-s col 按某列排序(可用 col 值:cpu, vss, rss, thr)
-t 顯示線程信息
-h 顯示幫助文檔
```
### 查看進程 UID
有兩種方案:
1. `adb shell dumpsys package <packagename> | grep userId=`
如:
```sh
$ adb shell dumpsys package org.mazhuang.guanggoo | grep userId=
userId=10394
```
2. 通過 ps 命令找到對應進程的 pid 之后 `adb shell cat /proc/<pid>/status | grep Uid`
如:
```sh
$ adb shell
gemini:/ $ ps | grep org.mazhuang.guanggoo
u0_a394 28635 770 1795812 78736 SyS_epoll_ 0000000000 S org.mazhuang.guanggoo
gemini:/ $ cat /proc/28635/status | grep Uid
Uid: 10394 10394 10394 10394
gemini:/ $
```
### 其它
如下是其它常用命令的簡單描述,前文已經專門講過的命令不再額外說明:
| 命令 | 功能 |
|-------|-----------------------------|
| cat | 顯示文件內容 |
| cd | 切換目錄 |
| chmod | 改變文件的存取模式/訪問權限 |
| df | 查看磁盤空間使用情況 |
| grep | 過濾輸出 |
| kill | 殺死指定 PID 的進程 |
| ls | 列舉目錄內容 |
| mount | 掛載目錄的查看和管理 |
| mv | 移動或重命名文件 |
| ps | 查看正在運行的進程 |
| rm | 刪除文件 |
| top | 查看進程的資源占用情況 |
## 常見問題
### 啟動 adb server 失敗
**出錯提示**
```sh
error: protocol fault (couldn't read status): No error
```
**可能原因**
adb server 進程想使用的 5037 端口被占用。
**解決方案**
找到占用 5037 端口的進程,然后終止它。以 Windows 下為例:
```sh
netstat -ano | findstr LISTENING
...
TCP 0.0.0.0:5037 0.0.0.0:0 LISTENING 1548
...
```
這里 1548 即為進程 ID,用命令結束該進程:
```sh
taskkill /PID 1548
```
然后再啟動 adb 就沒問題了。
### com.android.ddmlib.AdbCommandRejectedException
在 Android Studio 里新建一個模擬器,但是用 adb 一直連接不上,提示:
```
com.android.ddmlib.AdbCommandRejectedException: device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.
```
在手機上安裝一個終端然后執行 su 提示沒有該命令,這不正常。
于是刪除該模擬器后重新下載安裝一次,這次就正常了。
## adb 的非官方實現
* [fb-adb](https://github.com/facebook/fb-adb) - A better shell for Android devices (for Mac).
## 致謝
感謝朋友們無私的分享與補充(排名不分先后)。
[zxning](https://github.com/zxning),[linhua55](https://github.com/linhua55),[codeskyblue](https://github.com/codeskyblue),[seasonyuu](https://github.com/seasonyuu),[fan123199](https://github.com/fan123199),[zhEdward](https://github.com/zhEdward),[0x8BADFOOD](https://github.com/0x8BADFOOD),[keith666666](https://github.com/keith666666),[shawnlinboy](https://github.com/shawnlinboy)。
## 參考鏈接
* [Android Debug Bridge](https://developer.android.com/studio/command-line/adb.html)
* [ADB Shell Commands](https://developer.android.com/studio/command-line/shell.html)
* [logcat Command-line Tool](https://developer.android.com/studio/command-line/logcat.html)
* [Android ADB命令大全](http://zmywly8866.github.io/2015/01/24/all-adb-command.html)
* [adb 命令行的使用記錄](https://github.com/ZQiang94/StudyRecords/blob/master/other/src/main/java/com/other/adb%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%9A%84%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95.md)
* [Android ADB命令大全(通過ADB命令查看wifi密碼、MAC地址、設備信息、操作文件、查看文件、日志信息、卸載、啟動和安裝APK等)](http://www.jianshu.com/p/860bc2bf1a6a)
* [那些做Android開發必須知道的ADB命令](http://yifeiyuan.me/2016/06/30/ADB%E5%91%BD%E4%BB%A4%E6%95%B4%E7%90%86/)
* [adb shell top](http://blog.csdn.net/kittyboy0001/article/details/38562515)
* [像高手一樣使用ADB命令行(2)](http://cabins.github.io/2016/03/25/UseAdbLikeAPro-2/)
[1]: #ip-地址
---
#### 參考文檔
* [Awesome Adb——一份超全超詳細的 ADB 用法大全](https://juejin.im/entry/57c00fe4c4c971006179838a)
* [Awesome Adb存檔](https://github.com/mzlogin/awesome-adb)
- 0-發現
- AndroidInterview-Q-A
- Android能讓你少走彎路的干貨整理
- LearningNotes
- temp
- temp11
- 部分地址
- 0-待辦任務
- 待補充列表
- 0-未分類
- AndroidView事件分發與滑動沖突處理
- Spannable
- 事件分發機制詳解
- 1-Java
- 1-Java-01基礎
- 未歸檔
- 你應該知道的JDK知識
- 集合框架
- 1-Java-04合集
- Java之旅0
- Java之旅
- JAVA之旅01
- JAVA之旅02
- JAVA之旅03
- JAVA之旅04
- JAVA之旅05
- JAVA之旅06
- JAVA之旅07
- JAVA之旅08
- JAVA之旅09
- java之旅1
- JAVA之旅10
- JAVA之旅11
- JAVA之旅12
- JAVA之旅13
- JAVA之旅14
- JAVA之旅15
- JAVA之旅16
- JAVA之旅17
- JAVA之旅18
- JAVA之旅19
- java之旅2
- JAVA之旅20
- JAVA之旅21
- JAVA之旅22
- JAVA之旅23
- JAVA之旅24
- JAVA之旅25
- JAVA之旅26
- JAVA之旅27
- JAVA之旅28
- JAVA之旅29
- java之旅3
- JAVA之旅30
- JAVA之旅31
- JAVA之旅32
- JAVA之旅33
- JAVA之旅34
- JAVA之旅35
- 1-Java-05辨析
- HashMapArrayMap
- Java8新特性
- Java8接口默認方法
- 圖解HashMap(1)
- 圖解HashMap(2)
- 2-Android
- 2-Android-1-基礎
- View繪制流程
- 事件分發
- AndroidView的事件分發機制和滑動沖突解決
- 自定義View基礎
- 1-安卓自定義View基礎-坐標系
- 2-安卓自定義View基礎-角度弧度
- 3-安卓自定義View基礎-顏色
- 自定義View進階
- 1-安卓自定義View進階-分類和流程
- 10-安卓自定義View進階-Matrix詳解
- 11-安卓自定義View進階-MatrixCamera
- 12-安卓自定義View進階-事件分發機制原理
- 13-安卓自定義View進階-事件分發機制詳解
- 14-安卓自定義View進階-MotionEvent詳解
- 15-安卓自定義View進階-特殊形狀控件事件處理方案
- 16-安卓自定義View進階-多點觸控詳解
- 17-安卓自定義View進階-手勢檢測GestureDetector
- 2-安卓自定義View進階-繪制基本圖形
- 3-安卓自定義View進階-畫布操作
- 4-安卓自定義View進階-圖片文字
- 5-安卓自定義View進階-Path基本操作
- 6-安卓自定義View進階-貝塞爾曲線
- 7-安卓自定義View進階-Path完結篇偽
- 8-安卓自定義View進階-Path玩出花樣PathMeasure
- 9-安卓自定義View進階-Matrix原理
- 通用類介紹
- Application
- 2-Android-2-使用
- 2-Android-02控件
- ViewGroup
- ConstraintLayout
- CoordinatorLayout
- 2-Android-03三方使用
- Dagger2
- Dagger2圖文完全教程
- Dagger2最清晰的使用教程
- Dagger2讓你愛不釋手-終結篇
- Dagger2讓你愛不釋手-重點概念講解、融合篇
- dagger2讓你愛不釋手:基礎依賴注入框架篇
- 閱讀筆記
- Glide
- Google推薦的圖片加載庫Glide:最新版使用指南(含新特性)
- rxjava
- 這可能是最好的RxJava2.x入門教程完結版
- 這可能是最好的RxJava2.x入門教程(一)
- 這可能是最好的RxJava2.x入門教程(三)
- 這可能是最好的RxJava2.x入門教程(二)
- 這可能是最好的RxJava2.x入門教程(五)
- 這可能是最好的RxJava2.x入門教程(四)
- 2-Android-3-優化
- 優化概況
- 各種優化
- Android端秒開優化
- apk大小優化
- 內存分析
- 混淆
- 2-Android-4-工具
- adb命令
- 一鍵分析Android的BugReport
- 版本控制
- git
- git章節簡述
- 2-Android-5-源碼
- HandlerThread 源碼分析
- IntentService的使用和源碼分析
- 2-Android-9-辨析
- LRU算法
- 什么是Bitmap
- 常見圖片壓縮方式
- 3-Kotlin
- Kotlin使用筆記1-草稿
- Kotlin使用筆記2
- kotlin特性草稿
- Kotlin草稿-Delegation
- Kotlin草稿-Field
- Kotlin草稿-object
- 4-JavaScript
- 5-Python
- 6-Other
- Git
- Gradle
- Android中ProGuard配置和總結
- gradle使用筆記
- Nexus私服搭建
- 編譯提速最佳實踐
- 7-設計模式與架構
- 組件化
- 組件化探索(OKR)
- 1-參考列表
- 2-1-組件化概述
- 2-2-gradle配置
- 2-3-代碼編寫
- 2-4-常見問題
- 2-9-值得一讀
- 8-數據結構與算法
- 0臨時文件
- 漢諾塔
- 8-數據-1數據結構
- HashMap
- HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比較
- 遲到一年HashMap解讀
- 8-數據-2算法
- 1個就夠了
- Java常用排序算法(必須掌握的8大排序算法)
- 常用排序算法總結(性能+代碼)
- 必須知道的八大種排序算法(java實現)
- 9-職業
- 閱讀
- 書單
- 面試
- 面試-01-java
- Java面試題全集駱昊(上)
- Java面試題全集駱昊(下)
- Java面試題全集駱昊(中)
- 面試-02-android
- 40道Android面試題
- 面試-03-開源源碼
- Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執行流程
- 面試-07-設計模式
- 面試-08-算法
- 面試-09-其他
- SUMMARY
- 版權說明
- temp111