Python封裝adb命令的操作詳解
引言
在日常的 Android 項(xiàng)目開發(fā)中,我們通常會使用 adb 命令來獲取連接設(shè)備的內(nèi)存、屏幕、CPU等信息,也會使用 gradle 命令來獲取項(xiàng)目構(gòu)建相關(guān)的 projects、tasks、dependencies等信息,還會使用 git 命令來獲取代碼 commit、log、diff 等信息。這些信息的獲取,每次都在command 中輸入相關(guān)命令進(jìn)行操作(有時命令記不住,還需要查詢一下),重復(fù)的操作讓人感到厭倦和疲乏?,F(xiàn)在,可以嘗試使用 python 來簡化這一部分工作,將常用的執(zhí)行命令封裝到 python 腳本中,每次想要獲取某個信息時,就直接執(zhí)行相關(guān) python 腳本。這樣就可以省去開發(fā)中的細(xì)碎工作。(將腳本一次寫好,使用到退休:))
python 準(zhǔn)備
使用 Python 腳本封裝常用的 adb、gradle、git 命令,首先需要對 python 有一定的基本了解。
使用 subprocess 模塊
subprocess
模塊是 Python 中執(zhí)行外部命令的標(biāo)準(zhǔn)庫。通過該模塊,可以執(zhí)行 adb、gradle、git 等命令,以及獲取命令輸出結(jié)果。
import subprocess result = subprocess.run(['adb', 'devices'], capture_output=True, text=True, check=True) print(result.stdout)
將執(zhí)行命令的操作簡單地封裝成一個方法:
def run_command(command): try: result = subprocess.run(command, check=True, text=True, capture_output=True) return result.stdout except subprocess.CalledProcessError as e: print(f"Error executing command: {e}") return None result = run_command(['adb', 'devices']) print(result)
如果要實(shí)時打印執(zhí)行命令的每一行結(jié)果,可以使用 subprocess.Popen
方法:
def run_command_process(command): try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: print("stop") break if output: print(output.strip()) return process.returncode except subprocess.CalledProcessError as e: print(f"Error executing command: {e}") return None
切換工作目錄路徑
使用 os
模塊中的 chdir
函數(shù)可以切換當(dāng)前工作目錄的路徑:
import os os.chdir(current_project_path)
執(zhí)行 adb 命令
在日常的 Android 項(xiàng)目開發(fā)中,通常使用 adb 命令來獲取屏幕、設(shè)備、應(yīng)用程序等信息。
首先定義一個執(zhí)行 adb 命令的基礎(chǔ)方法:
def run_adb_command(adb_path='adb', command=None): """ :param adb_path: adb 工具路徑,如果在系統(tǒng)環(huán)境中配置了adb路徑,則不需要傳遞,否則需要 :param command: 實(shí)際相關(guān)命令 :return: 執(zhí)行命令結(jié)果 """ if command is None: command = [] try: command.insert(0, adb_path) return subprocess.run(command, check=True, text=True, capture_output=True, encoding='utf-8') except subprocess.CalledProcessError as e: print(f"Error executing command: {e}") return None
操作組合-截屏
截屏算是 Android 開發(fā)中的一個頻繁操作。在通常情況下,截屏操作步驟為:在設(shè)備上點(diǎn)擊截屏 → 找到設(shè)備上存儲的截屏文件地址 → 使用 adb pull 將截屏文件保存到電腦上 → 在電腦上打開截屏文件(或者使用 Android Studio 的 Logcat 面板截屏)。如果使用 pythoh,那么就可以將這幾個步驟組合,然后寫成一個 pythoh 腳本。
第一步:截屏并保存到設(shè)備
- 獲取設(shè)備外部存儲根路徑命令:
adb shell echo '$EXTERNAL_STORAGE'
- 截屏命令:
adb shell screencap -p screen_cap_file_path
,screen_cap_file_path為截屏文件地址,該地址和名稱可以自定義 - 創(chuàng)建文件目錄:
adb shell mkdir -p file_dir
,file_dir 為文件目錄
def screen_cap(adb_path='adb'): """ 截屏并保存到設(shè)備外部存儲卡 /Pictures/Screenshots 目錄下,截屏文件名為規(guī)則為Screenshot_年月日_時分秒.png,例如:Screenshot_20220502_175425.png :param adb_path: adb 工具路徑 :return: 截屏文件路徑和名稱 """ current_time = time.strftime("%Y%m%d_%H%M%S", time.localtime()) screen_cap_name = 'Screenshot_' + current_time + '.png' # 獲取手機(jī)外部存儲目錄 external_result = run_adb_command(adb_path, ['shell', "'echo'", '$EXTERNAL_STORAGE']) external_dir = external_result.stdout.strip() android_file_separator = '/' screen_cap_file_dir = external_dir + android_file_separator + 'Pictures' + android_file_separator + 'Screenshots' # 創(chuàng)建文件夾 adb shell mkdir -p file_dir run_adb_command(adb_path, ['shell', 'mkdir', '-p', screen_cap_file_dir]) screen_cap_file_path = screen_cap_file_dir + android_file_separator + screen_cap_name screen_cap_result = run_adb_command(adb_path, ['shell', 'screencap', '-p', screen_cap_file_path]) if screen_cap_result.returncode == 0: return [screen_cap_file_path, screen_cap_name] else: print(screen_cap_result.stderr) return ["", ""]
第二步:保存截屏文件到電腦
- 保存截屏文件到電腦命令:
adb pull src_file_path des_file_path
,src_file_path 為截屏文件在設(shè)備上的地址,des_file_path 為截屏文件保存到電腦上的地址。
def pull_screen_cap(src_file_path, des_file_path, adb_path='adb'): """ 將截屏文件保存到電腦上 :param src_file_path: 設(shè)備截屏文件地址 :param des_file_path: 電腦上文件地址 :param adb_path: adb 工具路徑 :return: ture表示成功,否則失敗 """ pull_screen_cap_result = run_adb_command(adb_path, ['pull', src_file_path, des_file_path]) return pull_screen_cap_result.returncode == 0 def get_desktop_path(screen_cap_name): """ 獲取保存到電腦上的截屏文件路徑 :param screen_cap_name: 截屏文件名稱 :return: 電腦上桌面中的截屏文件路徑 """ desktop_path = os.path.join(os.path.expanduser("~"), "Desktop") return desktop_path + os.path.sep + screen_cap_name
第三步:在電腦上打開截屏文件
- windows 打開文件命令:
start file_path
- mac 打開文件命令:
open file_path
def open_file(file_path): """ 在電腦上打開截屏文件 :param file_path: 電腦上的截屏文件地址 """ system = platform.system().lower() if system == "darwin": # macOS subprocess.run(["open", file_path]) elif system == "linux": # Linux subprocess.run(["xdg-open", file_path]) elif system == "windows": # Windows subprocess.run(["start", file_path], shell=True) else: print("Unsupported operating system.")
將上面步驟組合在一起:
if __name__ == '__main__': screen_cap_file_path, screen_cap_name = screen_cap() if len(screen_cap_file_path) > 0: des_file_path = get_desktop_path(screen_cap_name) result = pull_screen_cap(screen_cap_file_path, des_file_path) if result: print(f"Screenshot path: {des_file_path}") open_file(des_file_path) else: print("Failed to take a screenshot")
將上面的代碼放到 screencap.py 中,在需要截屏的時候,執(zhí)行 python3 screencap.py
腳本,就可以自動截屏并在電腦上打開截屏文件。
操作簡化-基礎(chǔ)信息
獲取設(shè)備上的三方應(yīng)用程序的 Main Activity(啟動 Activity)信息
如果直接使用 adb 命令,獲取設(shè)備上的三方應(yīng)用程序的 Main Activity(啟動 Activity)信息,是非常繁瑣的。利用 python,可以將操作簡化,而且將信息格式化。
第一步:獲取三方應(yīng)用程序包名
- 獲取設(shè)備上安裝的三方應(yīng)用程序列表命令:
adb shell pm list packages -3 -f
- 利用正則表達(dá)式找到應(yīng)用程序包名:
r"base.apk=(\S+)"
def get_third_party_app_activities(adb_path='adb'): """ 獲取設(shè)備上的三方應(yīng)用程序的 main activity :param adb_path: adb 工具的路徑 :return:三方應(yīng)用程序的 main activity 信息 """ result = run_adb_command(adb_path, ['shell', 'pm', 'list', 'packages', '-3', '-f']) third_party_app_main_activities = [] if result is not None: # 使用正則表達(dá)式提取包名 package_names = re.findall(r"base.apk=(\S+)", result) print(package_names) # 獲取每個應(yīng)用程序的主活動 for package_name in package_names: activity = get_main_activity(package_name) if activity: third_party_app_main_activities.append(f"Package: {package_name}, Main Activity: {activity}") return '\n'.join(third_party_app_main_activities)
第二步:通過應(yīng)用程序包名獲取 Main Activity
- 獲取應(yīng)用程序 Main Activity 命令:
adb shell dumpsys package package_name | grep -A 1 MAIN
def get_main_activity(package_name, adb_path='adb'): """ 根據(jù)包名獲取 main activity :param package_name: 應(yīng)用程序包名 :param adb_path: adb 工具的路徑 :return: main activity 信息,例如:com.tencent.mm/.ui.LauncherUI """ try: result = run_adb_command(adb_path, ['shell', 'dumpsys', 'package', package_name, '|', 'grep', '-A', '1', 'MAIN']) if result is not None: # 使用正則表達(dá)式提取 main activity text = result.strip() end_flag = 'filter' end_index = text.index(end_flag) android_file_separator = '/' start_flag = package_name + android_file_separator start_index = text.index(start_flag, 0, end_index) main_activity = text[start_index:end_index] if main_activity.startswith(package_name): return main_activity else: print("Error extracting main activity: index-" + package_name) return None else: print("Error extracting main activity: code-" + package_name) return None except AttributeError: print("Error extracting main activity: caught-" + package_name)
執(zhí)行上面代碼可以看到:
if __name__ == "__main__": print(get_third_party_app_activities()) 輸出結(jié)果: Package: com.tencent.mm, Main Activity: com.tencent.mm/.ui.LauncherUI Package: com.sangfor.vpn.client.phone, Main Activity: com.sangfor.vpn.client.phone/.WelcomeActivity Package: com.huawei.cloud, Main Activity: com.huawei.cloud/.wi.WIActivity Package: com.meishe.myvideoapp, Main Activity: com.meishe.myvideoapp/com.meishe.myvideo.activity.MainActivity Package: com.screeclibinvoke, Main Activity: com.screeclibinvoke/.component.activity.AppStartActivity Package: com.tencent.wework, Main Activity: com.tencent.wework/.launch.LaunchSplashActivity
獲取設(shè)備上當(dāng)前應(yīng)用程序的當(dāng)前Activity
獲取設(shè)備上當(dāng)前應(yīng)用程序的當(dāng)前Activity,對于快速定位代碼是非常有幫助的。利用 python 可以輕松搞定:
def get_top_activity(adb_path='adb'): return _run_adb_command(adb_path, ['shell', 'dumpsys', 'activity', 'top', '|', 'grep', 'ACTIVITY', '|', 'tail', '-n', '1'])
執(zhí)行結(jié)果:
ACTIVITY com.tencent.wework/.login.controller.LoginWxAuthActivity 8e93087 pid=22406
小結(jié)
上面簡單介紹了使用 python 執(zhí)行 adb 命令獲取截屏、三方應(yīng)用程序Main Activity、當(dāng)前應(yīng)用程序當(dāng)前Activity信息,可以看到在 python 中,將相關(guān) adb 命令操作組合或簡化后輸出,能夠快速的得到關(guān)鍵信息,這就可以省去了部分瑣碎時間。其它信息的獲取,例如:
- 獲取設(shè)備基礎(chǔ)信息:adb shell getprop
- 獲取設(shè)備屏幕信息:adb shell wm size 或 adb shell wm density
- 獲取設(shè)備cpu信息:adb shell cat /proc/cpuinfo
- 獲取設(shè)備memory信息:adb shell cat /proc/meminfo
- 其它
也可以使用 python,這里就不再將每一個列舉。
以上就是Python封裝adb命令的操作詳解的詳細(xì)內(nèi)容,更多關(guān)于Python封裝adb命令的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python argparse 解析命令行參數(shù)模塊詳情
這篇文章主要介紹了Python argparse 解析命令行參數(shù)模塊詳情,argparse是python用于解析命令行參數(shù)和選項(xiàng)的標(biāo)準(zhǔn)模塊,用于代替已經(jīng)過時的optparse模塊2022-07-07python中not、and和or的優(yōu)先級與詳細(xì)用法介紹
這篇文章主要給大家介紹了python中not、and和or的優(yōu)先級與詳細(xì)用法介紹,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11python通過urllib2獲取帶有中文參數(shù)url內(nèi)容的方法
這篇文章主要介紹了python通過urllib2獲取帶有中文參數(shù)url內(nèi)容的方法,涉及Python中文編碼的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03Python緩存技術(shù)實(shí)現(xiàn)過程詳解
這篇文章主要介紹了Python緩存技術(shù)實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09如何解決django-celery啟動后迅速關(guān)閉
在本篇文章里小編給大家整理的是關(guān)于django-celery啟動后迅速關(guān)閉的解決方法,有需要的朋友們學(xué)習(xí)下。2019-10-10python的tkinter、socket庫開發(fā)tcp的客戶端和服務(wù)端詳解
本文介紹了TCP通訊流程和開發(fā)步驟,包括客戶端和服務(wù)端的實(shí)現(xiàn),客戶端使用Python的tkinter庫實(shí)現(xiàn)圖形化界面,服務(wù)端使用socket庫監(jiān)聽連接并處理消息,文章還提供了客戶端和服務(wù)端的代碼示例2025-01-01Python中playwright啟動瀏覽器與常見運(yùn)行方式詳解
Playwright是一個功能強(qiáng)大的工具,可以幫助開發(fā)人員自動化測試、網(wǎng)頁截圖、信息提取等任務(wù),本文主要介紹了如何使用Playwright來啟動瀏覽器,感興趣的可以了解下2024-05-05