AppAgent 源码 (AndroidController 类 )

news/2024/12/27 5:45:31/

1. AndroidController 类

AndroidController 类,用于通过 ADB(Android Debug Bridge)命令控制连接的 Android 设备。它提供了一系列方法来实现常见的 Android 设备操作,例如获取屏幕截图、获取 XML 布局文件、模拟点击、输入文本、滑动和长按操作。

以下是详细解释:

  1. 初始化 (__init__)

    • 输入参数
      • device: 表示设备的标识符(通过 adb devices 命令可以获取)。
    • 初始化内容
      • self.device: 保存设备 ID。
      • self.screenshot_dir: 保存截图的默认路径(从全局 configs 中获取)。
      • self.xml_dir: 保存 XML 文件的默认路径(从全局 configs 中获取)。
      • self.width, self.height: 通过调用 get_device_size() 获取设备屏幕宽高。
      • self.backslash: 为了处理路径中的反斜杠。
  2. 获取设备屏幕尺寸 (get_device_size)

    • 功能
      • 执行 adb shell wm size 命令以获取设备屏幕的分辨率。
      • 如果获取成功,解析返回值(例如 "Physical size: 1080x1920")并提取宽高。
      • 如果失败,返回 (0, 0)
  3. 获取屏幕截图 (get_screenshot)

    • 功能
      • 将设备屏幕截图保存到设备的指定目录,并将其拉取到本地。
    • 步骤
      • 构造两个 ADB 命令:
        • screencap -p: 在设备上保存截图。
        • pull: 将截图从设备目录拉取到本地目录。
      • 执行命令并检查结果。
      • 如果成功,返回本地保存的文件路径;如果失败,返回错误信息。
  4. 获取 XML 布局文件 (get_xml)

    • 功能
      • 获取设备当前的 UI 布局并保存为 XML 文件,然后拉取到本地。
    • 步骤
      • 构造两个 ADB 命令:
        • uiautomator dump: 生成 XML 文件。
        • pull: 将 XML 文件从设备拉取到本地。
      • 执行命令并检查结果。
      • 如果成功,返回本地保存的文件路径;如果失败,返回错误信息。
  5. 返回操作 (back)

    • 功能
      • 模拟按下返回键。
    • 实现
      • 执行 adb shell input keyevent KEYCODE_BACK 命令。
  6. 点击操作 (tap)

    • 功能
      • 在屏幕的指定位置模拟点击。
    • 实现
      • 执行 adb shell input tap x y,其中 x, y 是点击位置的坐标。
  7. 文本输入 (text)

    • 功能
      • 模拟文本输入操作。
    • 处理特殊字符
      • 替换空格为 %s
      • 删除单引号('),防止命令解析错误。
    • 实现
      • 执行 adb shell input text input_str
  8. 长按操作 (long_press)

    • 功能
      • 模拟长按屏幕某个位置。
    • 实现
      • 执行 adb shell input swipe x y x y duration,通过滑动命令模拟长按,duration 表示持续时间。
  9. 滑动操作 (swipe)

    • 功能
      • 模拟从某个起点朝某个方向滑动。
    • 步骤
      • 根据屏幕宽度计算滑动距离(短、中、长)。
      • 根据方向设置偏移量:
        • 上:(0, -2 * unit_dist)
        • 下:(0, 2 * unit_dist)
        • 左:(-unit_dist, 0)
        • 右:(unit_dist, 0)
      • 构造并执行 adb shell input swipe 命令。
  10. 精确滑动 (swipe_precise)

    • 功能
      • 模拟从指定起点滑动到指定终点。
    • 实现
      • 接收起点和终点的坐标 (start_x, start_y)(end_x, end_y)
      • 构造并执行 adb shell input swipe 命令,指定滑动路径和持续时间。

2. AndroidController 类源码

class AndroidController:def __init__(self, device):self.device = deviceself.screenshot_dir = configs["ANDROID_SCREENSHOT_DIR"]self.xml_dir = configs["ANDROID_XML_DIR"]self.width, self.height = self.get_device_size()self.backslash = "\\"def get_device_size(self):adb_command = f"adb -s {self.device} shell wm size"result = execute_adb(adb_command)if result != "ERROR":return map(int, result.split(": ")[1].split("x"))return 0, 0def get_screenshot(self, prefix, save_dir):cap_command = (f"adb -s {self.device} shell screencap -p "f"{os.path.join(self.screenshot_dir, prefix + '.jpg').replace(self.backslash, '/')}")pull_command = (f"adb -s {self.device} pull "f"{os.path.join(self.screenshot_dir, prefix + '.jpg').replace(self.backslash, '/')} "f"{os.path.join(save_dir, prefix + '.jpg')}")result = execute_adb(cap_command)if result != "ERROR":result = execute_adb(pull_command)if result != "ERROR":return os.path.join(save_dir, prefix + ".jpg")return resultreturn resultdef get_xml(self, prefix, save_dir):dump_command = (f"adb -s {self.device} shell uiautomator dump "f"{os.path.join(self.xml_dir, prefix + '.xml').replace(self.backslash, '/')}")pull_command = (f"adb -s {self.device} pull "f"{os.path.join(self.xml_dir, prefix + '.xml').replace(self.backslash, '/')} "f"{os.path.join(save_dir, prefix + '.xml')}")result = execute_adb(dump_command)if result != "ERROR":result = execute_adb(pull_command)if result != "ERROR":return os.path.join(save_dir, prefix + ".xml")return resultreturn resultdef back(self):adb_command = f"adb -s {self.device} shell input keyevent KEYCODE_BACK"ret = execute_adb(adb_command)return retdef tap(self, x, y):adb_command = f"adb -s {self.device} shell input tap {x} {y}"ret = execute_adb(adb_command)return retdef text(self, input_str):input_str = input_str.replace(" ", "%s")input_str = input_str.replace("'", "")adb_command = f"adb -s {self.device} shell input text {input_str}"ret = execute_adb(adb_command)return retdef long_press(self, x, y, duration=1000):adb_command = (f"adb -s {self.device} shell input swipe {x} {y} {x} {y} {duration}")ret = execute_adb(adb_command)return retdef swipe(self, x, y, direction, dist="medium", quick=False):unit_dist = int(self.width / 10)if dist == "long":unit_dist *= 3elif dist == "medium":unit_dist *= 2if direction == "up":offset = 0, -2 * unit_distelif direction == "down":offset = 0, 2 * unit_distelif direction == "left":offset = -1 * unit_dist, 0elif direction == "right":offset = unit_dist, 0else:return "ERROR"duration = 100 if quick else 400adb_command = f"adb -s {self.device} shell input swipe {x} {y} {x+offset[0]} {y+offset[1]} {duration}"ret = execute_adb(adb_command)return retdef swipe_precise(self, start, end, duration=400):start_x, start_y = startend_x, end_y = endadb_command = f"adb -s {self.device} shell input swipe {start_x} {start_x} {end_x} {end_y} {duration}"ret = execute_adb(adb_command)return ret

3. 例子演示

from and_controller import AndroidController
import osdevice_id = "your connected device id"# 初始化 AndroidController
controller = AndroidController(device=device_id)# 打印设备屏幕分辨率
width, height = controller.get_device_size()
print(f"Device screen resolution: {width}x{height}")
<class 'os._Environ'>
<class 'dict'>
Warning! No module named 'sounddevice'
Warning! No module named 'matplotlib'
Warning! No module named 'keras'
Device screen resolution: 1220x2712
import time
import datetime
app = "gaode"
root_dir = "./"
work_dir = os.path.join(root_dir, "apps")
if not os.path.exists(work_dir):os.mkdir(work_dir)
work_dir = os.path.join(work_dir, app)
if not os.path.exists(work_dir):os.mkdir(work_dir)
demo_dir = os.path.join(work_dir, "demos")
if not os.path.exists(demo_dir):os.mkdir(demo_dir)
demo_timestamp = int(time.time())
task_name = datetime.datetime.fromtimestamp(demo_timestamp).strftime("self_explore_%Y-%m-%d_%H-%M-%S")
task_dir = os.path.join(demo_dir, task_name)
os.mkdir(task_dir)# 截取屏幕截图并保存
screenshot_path = controller.get_screenshot("test_screenshot", task_dir)
if screenshot_path != "ERROR":print(f"Screenshot saved at: {screenshot_path}")
else:print("Failed to capture screenshot.")
Screenshot saved at: ./apps\gaode\demos\self_explore_2024-12-26_01-21-10\test_screenshot.jpg
# 获取并保存 XML 文件
xml_path = controller.get_xml("test_layout", task_dir)
if xml_path != "ERROR":print(f"XML layout saved at: {xml_path}")
else:print("Failed to capture XML layout.")
XML layout saved at: ./apps\gaode\demos\self_explore_2024-12-26_01-21-10\test_layout.xml

项目结构:
在这里插入图片描述

# 模拟返回按键
result = controller.back()
print(f"Back key result: {result}")    
Back key result: 

如果成功,result结果为空

# 模拟点击屏幕坐标 (100, 200)
result = controller.tap(100, 200)
# 模拟输入文本
result = controller.text("Hello World")
# 模拟长按屏幕坐标 (150, 300) 持续 2 秒
result = controller.long_press(150, 300, duration=2000)
# 模拟从 (100, 500) 向上滑动
result = controller.swipe(100, 500, "up")
# 模拟从 (100, 200) 滑动到 (300, 400)
result = controller.swipe_precise((100, 200), (300, 400), duration=1000)

http://www.ppmy.cn/news/1558450.html

相关文章

【第2篇】 Python与数据库基础

1. 数据库的基本概念 1.1 表&#xff08;Table&#xff09; 表是数据库中存储数据的基本单位&#xff0c;由行和列组成。例如&#xff1a;users 表可以存储用户信息&#xff0c;每一行代表一个用户&#xff0c;每一列代表用户的属性&#xff08;如姓名、年龄&#xff09;。 …

Android 之 List 简述

一、简单创建方式 Android 开发中&#xff0c;列表有很多种类&#xff0c;如ArrayList、LinkedList、List、MutableList等&#xff0c;创建列表的方式如下所示&#xff1a; fun listDemo() {// 使用 listOf 创建不可变的空列表val list listOf<Int>()val list1 listOf…

【C语言】库函数常见的陷阱与缺陷(二):字符串转化函数[3]--strtol

C语言库函数strtol用于将字符串转换成整数,其功能强大且灵活,但在使用过程中也存在一些常见的陷阱与缺陷。 一、功能与用法 strtol(string to long)函数用于将字符串转换为长整数。允许指定转换的基数(如十进制、十六进制等),并能更好地处理错误和溢出情况,因此比ato…

抖音小程序登录(前端通过tt.login获取code换取openId)

抖音小程序登录 抖音开放平台小程序登录&#xff1a; https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/tutorial/basic-ability/microapp-login 前端(通过tt.login获取code) 流程 静默登录依赖小程序 API tt.login&#xff0c;把tt.loginsuccess 回调…

jvm排查问题-实践追踪问题 与思路--堆内堆外内存泄漏排查方针

概述 排查问题的一般思路是:现象 ——> 直接原因 ——>根本原因。 从问题现象出发,可以分为 应用逻辑问题、资源使用问题、虚拟机异常: 应用逻辑可能导致报错增加、死锁、程序退出等;资源问题主要集中在CPU上升和内存上升(OOM Kill);虚拟机问题通常包括GC问题、进…

打造两轮差速机器人fishbot:从零开始构建移动机器人

大家好&#xff0c;我是梦笔生花&#xff0c;我们一起来动手创建一个两轮差速的移动机器人fishbot。 机器人除了雷达之外&#xff0c;还需要IMU加速度传感器以及可以驱动的轮子&#xff0c;我们曾介绍过机器人学部分&#xff0c;曾对两差速模型进行过介绍&#xff0c;所以我们…

uniapp 基于xgplayer(西瓜视频) + renderjs开发,实现APP视频播放

背景&#xff1a;在uniapp中因原生video组件功能有限&#xff0c;选择引入xgplayer库来展示视频播放等功能。并且APP端无法操作dom&#xff0c;所以使用了renderjs。 其他的不多说&#xff0c;主要列举一下renderjs中需要注意的点&#xff1a; 1、使用&#xff1a;在标签后&…

【YOLO】(基础篇一)YOLO介绍

YOLO YOLO&#xff08;You Only Look Once&#xff09;是一种用于实时物体检测的算法&#xff0c;由Joseph Redmon等人提出。它能够同时进行物体分类和定位&#xff0c;并且因其速度和效率而广受赞誉。 工作原理 假设我们要对这张猫的图片完成目标检测&#xff0c;需要框选出…