如何使用 Python 來擴充套件 adb 命令?
生死看淡,不服就幹!
0x00 緣起
作為一個標準的“工程師”,在控制檯使用命令才是我們最終的歸宿,看起來才更像大牛,當然,這都是題外話。
在進行 Android 開發時, adb
是我們最常使用的命令之一。
當你正在除錯程式碼邏輯時,產品同學過來說:“你把你剛發出來的那個提測的 APK 給我裝一下唄。”雖然有一萬隻草尼瑪從心中奔騰而過,但還是會屈服於產品的“美貌”,給他安裝提測包。接下來,會做什麼事情呢:
- 將產品同學的手機通過 USB 連線(有時候,你還需要手動去開啟 USB 除錯);
- 找到要安裝的 APK 檔案;
- 使用 adb 命令安裝上面步驟中找到的那個 APK。
就在這個時候,你電腦上同時插著多臺裝置,輸入的命令在執行就直接報錯了:
error: more than one device/emulator adb: error: failed to get feature set: more than one device/emulator - waiting for device - error: more than one device/emulator
超出了 adb
所支援的裝置數,所以,你的步驟變得更非常地複雜。
-
adb devices
列出你當前的裝置列表,然後拷貝你要安裝的裝置Device Id
; - 使用
adb -s deviceId install ....
來進行 APK 安裝。
這個步驟重複超過 10 次,你還在重複,請仔細閱讀下文,本文將教會你如何解放自己的雙手,讓你有更多的時間做更多的需求,開不開心[手動壞笑]。
0x01 需求分析
上面問題的痛點是:我在執行命令時,不得不去手動拿到“Device Id”,並且手動設定上去。
類似案例分析:在使用 Android Studio Debug 執行 App 的時候,會讓你先選擇你要安裝到的裝置,然後才會進行編譯、安裝、啟動頁面。
所以,需要優化“Device Id”的獲取方式。我們可以使用指令碼來獲取當前連線在電腦上的裝置,並且給出一個輸入的入口,讓使用者選擇要執行命令的裝置。
0x02 程式碼實現
在這裡,筆者使用 Python 來實現自動獲取“Device Id”的功能。
寫好指令碼,世界會更加美好。
-
獲取裝置列表
Android SDK 中提供的 adb 工具給我們提供了很多功能,獲取裝置的命令如下:
adb devices
所以,只需要使用 Python 執行這條 Shell 指令碼,並解析指令碼輸出結果,就可以拿到裝置列表。程式碼邏輯如下:
def readDevicesList(): p=os.popen('adb devices') devicesList=p.read() p.close() lists = devicesList.split("\n") devicesNames = [] for item in lists: if(item.strip() == ""): continue elif(item.startswith("List of")) : continue else: devicesNames.append(item.split("\t")[0]) return devicesNames
如上,就可以拿到當前連線在 USB 的裝置列表。
-
讓使用者選擇裝置
從上面拿到了裝置列表,讓使用者輸入一個給定的 index,然後去取 index 所對應的
Device Id
。def selectDevices(devicesIds): print "Please Select Devices:" i = 0 for deviceId in devicesIds : print "\033[1;34m " + str(i) + ": " + getRealDeviceName(deviceId) + "\033[0m" i += 1 print "\033[1;34m e: exit\033[0m" try: inputIndex = raw_input("Enter your device index [0, " + str(i) + ") :") value = int(inputIndex) if value >= i: raise Exception("index is to big.") return value except (KeyboardInterrupt, SystemExit) : return -1 except Exception as e: if "e" == inputIndex or "E" == inputIndex: return -1 else: print "\033[1;31mYour select index is error, please try again.\033[0m" return selectDevices(devicesIds)
在這裡,為了有更好的輸出結果,我們需要處理 KeyboardInterrupt , SystemExit 的異常事件,遇到這種異常的時候,就直接終止。當然,我們還需要處理使用者輸入的字元,防止輸入非法字元,引起異常。
執行結果如下圖:
-
拼裝命令並執行在上面,已經拿到使用者要安裝的 APK 的
Device Id
, 下面我們根據使用者的輸入命令來生成我們自己的命令。def generateShellCommand(deviceId): shellCommand = "adb -s " + deviceId for i in range(1, len(sys.argv)): shellCommand += " " + repr(sys.argv[i]) print "execute shell command:" print "" + shellCommand return shellCommand
拿到生成的新命令,然後執行。
if __name__ == '__main__': devicesNames = readDevicesList() if len(devicesNames) <= 0: print "Please connect your devices." elif len(devicesNames) == 1: shellCommand = generateShellCommand(devicesNames[0]) execShellCommand(shellCommand) else : index = selectDevices(devicesNames) if index != -1: useDeviceName = devicesNames[index] shellCommand = generateShellCommand(useDeviceName) execShellCommand(shellCommand)
-
優化顯示裝置名稱
在前面獲取到的
Device Id
列表,直接展示出來給使用者選擇,其實不太友好,誰會記得自己手機的Device Id
呢。是吧。所以我們需要在進行一波操作,將Device Id
轉換成使用者可以識別的裝置名稱。def getRealDeviceName(deviceId): p = os.popen('adb -s ' + deviceId + ' shell getprop ro.product.manufacturer') manufacturer = p.read() p.close() p = os.popen('adb -s ' + deviceId + ' shell getprop ro.product.model') model = p.read() p.close() return manufacturer.strip() + " " + model.strip()
通過 adb 命令去拿到裝置的 manufacturer 與 model 資訊。
立竿見影的效果。
0x03 總結
Talk is cheap, show me the code.
有很多功能,我們可以一遍一遍的去寫手動執行,但是稍加處理,使用少量指令碼就可以處理這些問題。追求效率,釋放雙手。
歡迎關注我的公眾號,一起交流技術事。
