Python封裝adb命令的操作詳解
引言
在日常的 Android 項目開發(fā)中,我們通常會使用 adb 命令來獲取連接設(shè)備的內(nèi)存、屏幕、CPU等信息,也會使用 gradle 命令來獲取項目構(gòu)建相關(guān)的 projects、tasks、dependencies等信息,還會使用 git 命令來獲取代碼 commit、log、diff 等信息。這些信息的獲取,每次都在command 中輸入相關(guān)命令進(jìn)行操作(有時命令記不住,還需要查詢一下),重復(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)
如果要實時打印執(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 項目開發(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: 實際相關(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è)備上點擊截屏 → 找到設(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'
# 獲取手機外部存儲目錄
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實現(xiàn)B站UP主小助手詳解開發(fā)流程
功能是不是還挺豐富的,從寫第一行代碼到完成也就花了兩天不到的時間,這也證明了使用python開發(fā)的高效率,下面來說說這些功能開發(fā)中我遇到了哪些問題,我又是如何解決的2022-02-02
Python實現(xiàn)將mp3音頻格式轉(zhuǎn)換為wav格式
這篇文章主要介紹了利用python寫了這個小工具,可以批量進(jìn)行mp3音頻格式轉(zhuǎn)換為wav格式,文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下2022-01-01
Python實現(xiàn)yaml與json文件批量互轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了如何利用Python語言實現(xiàn)yaml與json文件的批量互轉(zhuǎn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動手嘗試一下2022-07-07
一文詳解如何在Python中進(jìn)行數(shù)學(xué)建模
數(shù)學(xué)建模是數(shù)據(jù)科學(xué)中使用的強大工具,通過數(shù)學(xué)方程和算法來表示真實世界的系統(tǒng)和現(xiàn)象,本文將指導(dǎo)大家完成Python中的數(shù)學(xué)建模過程,感興趣的可以了解下2024-11-11
在Python中操作MongoDB的詳細(xì)教程和案例分享
MongoDB是一個高性能、開源、無模式的文檔型數(shù)據(jù)庫,非常適合存儲JSON風(fēng)格的數(shù)據(jù),Python作為一種廣泛使用的編程語言,通過PyMongo庫可以方便地與MongoDB進(jìn)行交互,本文將詳細(xì)介紹如何在Python中使用PyMongo庫來操作MongoDB數(shù)據(jù)庫,需要的朋友可以參考下2024-08-08

