Appium Debug Bridge
Published in:2024-11-21 |
Words: 1.8k | Reading time: 9min | reading:

Appium Debug Bridge

ADB

install

1
https://developer.android.com/studio?hl=zh-cn#command-line-tools-only

appium

install

  • server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
https://github.com/appium/appium
#install
npm i -g appium
#install driver
appium driver install uiautomator2

# Start the server on the default host (0.0.0.0) and port (4723)
appium server
# You can also omit the 'server' subcommand
appium
# Start the server on the given host, port and use a custom base path prefix (the default prefix is '/')
appium --address 127.0.0.1 --port 9000 --base-path /wd/hub
#use
appium

python selenium

appium_adb_app.md

automatic test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# from venv import logger
#
from appium import webdriver
from time import sleep

from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from loguru import logger


@logger.catch
def appium_init():
"""
appium catch video
:return:
"""
delay_time = 5

desired_caps = {
'platformName': 'Android', # 或 'iOS',取决于你的设备
'platformVersion': '10', # 设备的 Android 版本
'deviceName': 'Android', # 模拟器的设备名或连接的设备名
'appPackage': 'com.ayay.yoga', # 替换为你的 App 包名
'appActivity': '.MainActivity', # 替换为你的主 Activity
'noReset': True, # 不重置应用
'fullContextIgnore': True,
'automationName': 'UiAutomator2', # Android 使用 UiAutomator2
}

# 创建 Appium WebDriver 实例
# 创建 UiAutomator2Options 对象,并设置所需的能力
options = UiAutomator2Options()
# options.add_argument("--no-reset") # 用于传递命令行参数,不是能力配置
options.platform_name = "Android"
options.platform_version = "10" # 目标设备的 Android 版本
options.device_name = "emulator-5554" # 模拟器或设备名
options.app_package = "com.ayay.yoga" # 替换为你的 App 包名
options.app_activity = "com.ayay.yoga.MainActivity" # 替换为你的 Activity 名称
options.no_reset = True # 确保传递布尔值

capabilities = dict(
platformName='Android',
automationName='uiautomator2',
deviceName='Android',
appPackage='com.ayay.yoga',
appActivity='.MainActivity',
language='en',
locale='US'
)

# 连接到 Appium 服务器
driver = webdriver.Remote('http://localhost:4723', options=UiAutomator2Options().load_capabilities(capabilities))

# 等待应用加载
sleep(delay_time)

def click_element_by_xpath(xpath):
"""通过 XPath 查找并点击元素"""
# element = driver.find_element(xpath)
element_faxian = driver.find_element(by=AppiumBy.XPATH, value=xpath)
element_faxian.click()

def click_element_by_id(element_id):
"""通过 ID 查找并点击元素"""
element = driver.find_element(by=AppiumBy.ID, value=element_id)
element.click()

def swipe_to_center(x_offset, y_offset):
"""模拟点击屏幕中心"""
center_x = x_offset // 2
center_y = y_offset // 2
# TouchAction(driver).tap(x=center_x, y=center_y).perform()

sleep(delay_time)
# element = driver.find_element_by_android_uiautomator('new UiSelector().text("发现")')
# element_faxian = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="发现"]')
click_element_by_xpath('//*[@text="发现"]')
# element.click()
# element_faxian.click()
sleep(delay_time)
print('switch tab')

# 1. 点击 "发现" 按钮(假设它的 XPath 是 '/hierarchy/.../发现')
# click_element_by_xpath('//*[@text="发现"]')

# 2. 点击 "全部课程" 按钮(假设它的 XPath 是 '/hierarchy/.../全部课程')
click_element_by_xpath('//*[@text="全部课程"]')
print("all course")
sleep(delay_time)

# 获取所有课程图片的元素(假设它们的 XPath 是 '/hierarchy/.../课程图片')
# 这里需要确保你能够定位到所有图片
images = driver.find_elements(by=AppiumBy.CLASS_NAME, value='android.widget.ImageView')
# images = driver.find_elements(by=AppiumBy.ID, value='//*[@resource-id="com.ayay.yoga:id/course_image"]')
print(str(len(images)) + 'image load result')
sleep(delay_time)

for img in images:
# 3. 点击每个课程图片
img.click()

# 4. 点击 "开始训练" 按钮(假设它的 XPath 是 '/hierarchy/.../开始训练')
click_element_by_xpath('//*[@text="开始训练"]')

# 5. 等待十秒
sleep(10)

# 6. 点击屏幕中心位置(假设屏幕大小为 1080x1920)
swipe_to_center(1080, 1920)

# 7. 点击左上角的按钮退出(假设它的 XPath 是 '/hierarchy/.../左上角按钮')
click_element_by_xpath('//*[@content-desc="Navigate up"]')

# 8. 点击 "结束训练" 按钮(假设它的 XPath 是 '/hierarchy/.../结束训练')
click_element_by_xpath('//*[@text="结束训练"]')

# 9. 等待十秒后继续循环
sleep(10)

# 完成操作后退出
driver.quit()


if __name__ == '__main__':
appium_init()


adb pull video

adb pull log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import subprocess
import time

from loguru import logger

from extract_mp4_links import extract_mp4_links, video_link_process
from src.pull_ld_video import adb_connect, adb_root

# 获取 adb 路径和设备 ID
ADB_PATH = r"C:\Users\DELL\Desktop\platform-tools\adb.exe"
DEVICE_ID = "emulator-5554" # 根据实际设备 ID 选择模拟器
package_name = 'com.ayay.yoga'

# 使用 adb shell pidof 命令获取指定包名的进程 ID
pid_command = [ADB_PATH, 'shell', 'pidof', '-s', package_name]
pid_process = subprocess.Popen(pid_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pid = pid_process.communicate()[0].decode('utf-8').strip()
if not pid:
logger.error(f"无法找到包名 '{package_name}' 对应的进程。")
else:
# 使用 adb logcat 命令抓取指定进程的日志
log_command = [ADB_PATH, 'logcat', '--pid=' + pid]


# 运行 adb logcat 获取模拟器日志
def get_simulator_log():
with open("simulator_log.txt", "w", encoding="utf-8") as f:
# 执行 adb logcat 命令并将输出写入文件
adb_connect()

# 2. 获取 root 权限(如果需要)
adb_root()
while True:
user_input = input("按下 'c' 键停止:")
# 判断用户输入是否为 'c'
if user_input.lower() == 'c':
logger.debug("你按下了 'c' 键!")
break # 按下 'c' 键后退出循环
process = subprocess.Popen(log_command, stdout=f, stderr=subprocess.PIPE)
process.communicate() # 等待 logcat 命令执行完成



# 获取日志
get_simulator_log()
logger.success("start video link process...")
video_link_process()

adb pull video from cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import subprocess
import os
import time

from anyio import sleep
from loguru import logger
from matplotlib.cbook import pts_to_midstep

# 获取 adb 路径和设备 ID
ADB_PATH = r"C:\Users\DELL\Desktop\platform-tools\adb.exe"
DEVICE_ID = "emulator-5554" # 根据实际设备 ID 选择模拟器


# 拉取指定路径的文件
@logger.catch
def adb_connect():
try:
# 确保连接到指定模拟器
result = subprocess.run([ADB_PATH, "-s", DEVICE_ID, "devices"], capture_output=True, text=True, check=True)
if "device" in result.stdout:
logger.debug(f"已连接到模拟器 {DEVICE_ID}")
else:
raise Exception(f"无法连接到模拟器 {DEVICE_ID}")
except subprocess.CalledProcessError as e:
logger.debug(f"连接模拟器失败: {e}")
raise


# 获取 root 权限
@logger.catch
def adb_root():
try:
# 获取 root 权限(如果模拟器支持)
subprocess.run([ADB_PATH, "-s", DEVICE_ID, "root"], check=True)
logger.debug("获取 root 权限成功!")
except subprocess.CalledProcessError as e:
logger.debug(f"无法获取 root 权限: {e}")


# 列出指定目录的文件
@logger.catch
def list_files(remote_dir):
try:
# 使用 adb shell ls 命令列出远程目录文件
result = subprocess.run(
[ADB_PATH, "-s", DEVICE_ID, "shell", "ls", remote_dir],
capture_output=True, text=True, check=True
)
files = result.stdout.splitlines() # 按行分割文件列表
return files
except subprocess.CalledProcessError as e:
logger.debug(f"获取文件列表失败: {e}")
return []


# 下载文件到本地
@logger.catch
def pull_files(remote_dir, local_dir, files):
try:
# 确保本地目录存在
os.makedirs(local_dir, exist_ok=True)

for file in files:
remote_file = os.path.join(remote_dir, file).replace("\\", "/") # 替换反斜杠为正斜杠
local_file = os.path.join(local_dir, file).replace("\\", "/") # 替换反斜杠为正斜杠
logger.debug(f"正在下载 {remote_file}{local_file}")

# 使用 adb pull 命令下载文件
subprocess.run([ADB_PATH, "-s", DEVICE_ID, "pull", remote_file, local_file], check=True)
logger.debug(f"{file} 下载完成!")
except subprocess.CalledProcessError as e:
logger.debug(f"下载文件失败: {e}")


# 主函数
@logger.catch
def main():
remote_dir = "/storage/emulated/0/Android/data/com.wtp.wtpilates/cache/video-cache" # 指定远程目录
local_dir = "./video/" # 本地保存路径

try:
# 1. 连接到模拟器
adb_connect()

# 2. 获取 root 权限(如果需要)
adb_root()

# 3. 列出远程目录中的文件
files = list_files(remote_dir)
if files:
logger.debug("文件列表:")
for file in files:
if not os.path.exists(os.path.join(local_dir, file)):
logger.debug(file)
else:
files.remove(file)
logger.debug(file + ", 已存在,跳过")
continue
# 4. 拉取文件到本地
pull_files(remote_dir, local_dir, files)
else:
logger.debug("没有找到文件。")

except Exception as e:
logger.debug(f"发生错误: {e}")


if __name__ == "__main__":
logger.add("../logs/ld_monitor.log", level="DEBUG", rotation="5MB")
while True:
main()
logger.debug("sleep 60 s..")
time.sleep(30)


see

Prev:
基于Easyocr的文字识别
Next:
Excel file parser