d.xpath('//*[@text="设置"]')d(resourceId="com.example:id/button")d(className="android.widget.Button")d(description="搜索")d.xpath('//android.widget.Button[@text="确定"]')element.click()element.long_click()element.double_click()element.set_text("Hello")element.clear_text()d.swipe(x1, y1, x2, y2)d.drag(x1, y1, x2, y2)d.pinch()d.rotate()d.app_start("com.example.app")d.app_stop("com.example.app")d.app_current()d.app_list()d.press('back'), d.press('home')d.press('volume_up')d.screen_on(), d.screen_off()element.wait(timeout=10)element.existselement.wait_gone()d.click(x, y)element.infod.window_size()d.info示例代码:
bash展开代码#!/usr/bin/env python3
"""
uiautomator2 完整能力演示
展示uiautomator2的所有主要功能
"""
import uiautomator2 as u2
import json
import os
import time
from datetime import datetime
from PIL import Image
def demo_all_capabilities():
"""
演示uiautomator2的所有能力
"""
print("🚀 uiautomator2 完整能力演示")
print("="*60)
try:
# 连接设备
d = u2.connect()
print(f"📱 已连接设备: {d.info.get('productName', 'Unknown')}")
print(f"📱 设备信息: {d.info}")
print()
# 1. 截图能力
print("📸 1. 截图功能")
print("-" * 30)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
screenshot_path = f"demo_screenshot_{timestamp}.png"
d.screenshot(screenshot_path)
print(f"✅ 截图已保存: {screenshot_path}")
print()
# 2. 元素查找能力
print("🔍 2. 元素查找功能")
print("-" * 30)
# 2.1 按文字查找
print("按文字查找:")
text_elements = d.xpath('//*[@text]').all()
print(f" 找到 {len(text_elements)} 个有文字的元素")
# 2.2 按类型查找
print("按类型查找:")
buttons = d.xpath('//android.widget.Button').all()
textviews = d.xpath('//android.widget.TextView').all()
imageviews = d.xpath('//android.widget.ImageView').all()
print(f" Button: {len(buttons)} 个")
print(f" TextView: {len(textviews)} 个")
print(f" ImageView: {len(imageviews)} 个")
# 2.3 按ID查找
print("按ID查找:")
id_elements = d.xpath('//*[@resource-id]').all()
print(f" 找到 {len(id_elements)} 个有ID的元素")
# 2.4 按内容描述查找
print("按内容描述查找:")
desc_elements = d.xpath('//*[@content-desc]').all()
print(f" 找到 {len(desc_elements)} 个有内容描述的元素")
print()
# 3. 元素操作能力
print("🎯 3. 元素操作功能")
print("-" * 30)
# 3.1 点击操作
print("点击操作:")
clickable_elements = d.xpath('//*[@clickable="true"]').all()
print(f" 找到 {len(clickable_elements)} 个可点击元素")
# 3.2 输入操作
print("输入操作:")
editable_elements = d.xpath('//*[@class="android.widget.EditText"]').all()
print(f" 找到 {len(editable_elements)} 个可编辑元素")
# 3.3 滑动操作
print("滑动操作:")
print(" 支持上下左右滑动")
print(" 支持指定距离和时间的滑动")
print()
# 4. 等待和检测能力
print("⏰ 4. 等待和检测功能")
print("-" * 30)
# 4.1 等待元素出现
print("等待元素出现:")
try:
# 等待某个元素出现(这里用系统时间作为示例)
clock_element = d.xpath('//*[@resource-id="com.android.systemui:id/clock"]')
if clock_element.exists:
print(" ✅ 系统时钟元素存在")
else:
print(" ❌ 系统时钟元素不存在")
except:
print(" ⚠️ 无法检测系统时钟")
# 4.2 检测应用状态
print("检测应用状态:")
current_app = d.app_current()
print(f" 当前应用: {current_app.get('package', 'Unknown')}")
print(f" 应用名称: {current_app.get('name', 'Unknown')}")
print()
# 5. 手势操作能力
print("👆 5. 手势操作功能")
print("-" * 30)
print("支持的手势:")
print(" - 点击 (click)")
print(" - 长按 (long_click)")
print(" - 双击 (double_click)")
print(" - 滑动 (swipe)")
print(" - 拖拽 (drag)")
print(" - 缩放 (pinch)")
print(" - 旋转 (rotate)")
print()
# 6. 应用控制能力
print("📱 6. 应用控制功能")
print("-" * 30)
# 6.1 应用启动
print("应用启动:")
print(" - 启动应用: d.app_start(package_name)")
print(" - 停止应用: d.app_stop(package_name)")
print(" - 清除应用数据: d.app_clear(package_name)")
# 6.2 应用信息
print("应用信息:")
installed_apps = d.app_list()
print(f" 已安装应用数量: {len(installed_apps)}")
print(" 前5个应用:")
for i, app in enumerate(installed_apps[:5], 1):
print(f" {i}. {app}")
print()
# 7. 设备控制能力
print("🔧 7. 设备控制功能")
print("-" * 30)
# 7.1 设备信息
print("设备信息:")
device_info = d.info
print(f" 屏幕尺寸: {device_info.get('displayWidth')}x{device_info.get('displayHeight')}")
print(f" 设备型号: {device_info.get('productName', 'Unknown')}")
print(f" Android版本: {device_info.get('version', 'Unknown')}")
# 7.2 设备操作
print("设备操作:")
print(" - 返回键: d.press('back')")
print(" - 主页键: d.press('home')")
print(" - 菜单键: d.press('menu')")
print(" - 电源键: d.press('power')")
print(" - 音量键: d.press('volume_up/volume_down')")
print()
# 8. 高级功能
print("🚀 8. 高级功能")
print("-" * 30)
# 8.1 坐标操作
print("坐标操作:")
width, height = d.window_size()
print(f" 屏幕中心坐标: ({width//2}, {height//2})")
print(" - 点击坐标: d.click(x, y)")
print(" - 滑动坐标: d.swipe(x1, y1, x2, y2)")
# 8.2 元素属性获取
print("元素属性获取:")
if text_elements:
first_element = text_elements[0]
print(f" 第一个元素信息:")
print(f" 文字: {first_element.text}")
print(f" 类名: {first_element.info.get('className', 'Unknown')}")
print(f" 资源ID: {first_element.info.get('resourceId', 'Unknown')}")
print(f" 位置: {first_element.info.get('bounds', {})}")
print(f" 可点击: {first_element.info.get('clickable', False)}")
print()
# 9. 实际演示
print("🎬 9. 实际演示")
print("-" * 30)
# 9.1 获取所有交互元素
interactive_elements = []
for element in d.xpath('//*').all():
info = element.info
if (info.get('clickable', False) or
info.get('focusable', False) or
info.get('contentDescription', '') or
info.get('text', '')):
interactive_elements.append({
'text': element.text or '',
'content_desc': info.get('contentDescription', ''),
'class_name': info.get('className', ''),
'clickable': info.get('clickable', False),
'bounds': info.get('bounds', {})
})
print(f"找到 {len(interactive_elements)} 个交互元素")
print("前10个交互元素:")
for i, element in enumerate(interactive_elements[:10], 1):
display_text = element['text'] or element['content_desc'] or '无文字'
print(f" {i:2d}. {display_text}")
print(f" 类型: {element['class_name']}")
print(f" 可点击: {element['clickable']}")
print()
print("✅ 演示完成!")
print("="*60)
print("📚 uiautomator2 主要能力总结:")
print("1. 📸 截图 - 获取手机屏幕截图")
print("2. 🔍 元素查找 - 按各种条件查找UI元素")
print("3. 🎯 元素操作 - 点击、输入、滑动等操作")
print("4. ⏰ 等待检测 - 等待元素出现、检测应用状态")
print("5. 👆 手势操作 - 各种复杂手势操作")
print("6. 📱 应用控制 - 启动、停止、管理应用")
print("7. 🔧 设备控制 - 控制设备按键、获取设备信息")
print("8. 🚀 高级功能 - 坐标操作、属性获取等")
print("9. 🤖 自动化 - 完整的UI自动化测试能力")
except Exception as e:
print(f"❌ 演示失败: {e}")
print("请确保:")
print("1. 设备已连接 (adb devices)")
print("2. 已开启USB调试")
print("3. 已安装uiautomator2 (pip install uiautomator2)")
if __name__ == "__main__":
demo_all_capabilities()
screenshot_with_boxes.py
bash展开代码import uiautomator2 as u2
import json
import os
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
import random
def get_screenshot_and_elements(device_id=None):
"""
获取手机截图和所有元素信息
"""
try:
# 连接设备
if device_id:
d = u2.connect(device_id)
else:
d = u2.connect() # 自动连接第一个设备
print(f"📱 已连接到设备: {d.info.get('productName', 'Unknown')}")
# 获取截图
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
screenshot_path = f"screenshot_{timestamp}.png"
d.screenshot(screenshot_path)
print(f"📸 截图已保存: {screenshot_path}")
# 获取所有元素(包括文字和其他可点击元素)
all_elements = []
# 获取所有文字元素
for element in d.xpath('//*[@text]').all():
if element.text and element.text.strip():
element_info = {
'text': element.text.strip(),
'bounds': element.info.get('bounds', {}),
'resource_id': element.info.get('resourceId', ''),
'class_name': element.info.get('className', ''),
'content_desc': element.info.get('contentDescription', ''),
'clickable': element.info.get('clickable', False),
'enabled': element.info.get('enabled', False),
'element_type': 'text'
}
all_elements.append(element_info)
# 获取所有可点击元素(按钮、图片等)
for element in d.xpath('//*[@clickable="true"]').all():
if not element.text or not element.text.strip(): # 避免重复添加有文字的元素
element_info = {
'text': element.text or element.info.get('contentDescription', '') or '可点击元素',
'bounds': element.info.get('bounds', {}),
'resource_id': element.info.get('resourceId', ''),
'class_name': element.info.get('className', ''),
'content_desc': element.info.get('contentDescription', ''),
'clickable': element.info.get('clickable', False),
'enabled': element.info.get('enabled', False),
'element_type': 'clickable'
}
all_elements.append(element_info)
# 保存到JSON文件
json_path = f"elements_{timestamp}.json"
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(all_elements, f, ensure_ascii=False, indent=2)
print(f"📝 元素信息已保存: {json_path}")
# 打印元素统计
text_elements = [e for e in all_elements if e['element_type'] == 'text']
clickable_elements = [e for e in all_elements if e['element_type'] == 'clickable']
print(f"\n🔍 发现 {len(all_elements)} 个元素:")
print(f" 📝 文字元素: {len(text_elements)} 个")
print(f" 🖱️ 可点击元素: {len(clickable_elements)} 个")
return screenshot_path, json_path, all_elements
except Exception as e:
print(f"❌ 执行失败: {e}")
return None, None, []
def draw_boxes_on_screenshot(screenshot_path, elements, output_path=None):
"""
在截图上绘制元素框
"""
try:
# 打开截图
with Image.open(screenshot_path) as img:
# 创建绘图对象
draw = ImageDraw.Draw(img)
# 使用指定的字体文件
try:
font_path = r"D:\xiedong_dev\company_model_proxy\daily-hot-mcp\Arial-Unicode-MS.ttf"
font = ImageFont.truetype(font_path, 16)
print(f"✅ 成功加载字体: {font_path}")
except Exception as e:
print(f"⚠️ 字体加载失败: {e}")
try:
font = ImageFont.truetype("arial.ttf", 16)
except:
try:
font = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 16)
except:
font = ImageFont.load_default()
print("⚠️ 使用默认字体")
# 定义颜色
colors = [
(255, 0, 0), # 红色
(0, 255, 0), # 绿色
(0, 0, 255), # 蓝色
(255, 255, 0), # 黄色
(255, 0, 255), # 紫色
(0, 255, 255), # 青色
(255, 128, 0), # 橙色
(128, 0, 255), # 紫色
]
print(f"🎨 开始绘制 {len(elements)} 个元素框...")
for i, element in enumerate(elements):
bounds = element.get('bounds', {})
if not bounds or not all(key in bounds for key in ['left', 'top', 'right', 'bottom']):
continue
# 获取坐标
left = int(bounds['left'])
top = int(bounds['top'])
right = int(bounds['right'])
bottom = int(bounds['bottom'])
# 选择颜色
color = colors[i % len(colors)]
# 绘制矩形框
draw.rectangle([left, top, right, bottom], outline=color, width=3)
# 准备标签文本
text = element.get('text', '')
if len(text) > 20:
text = text[:17] + "..."
# 绘制标签背景
text_bbox = draw.textbbox((0, 0), f"{i+1}: {text}", font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
# 标签位置(在框的上方)
label_x = left
label_y = max(0, top - text_height - 5)
# 绘制标签背景
draw.rectangle([label_x, label_y, label_x + text_width + 4, label_y + text_height + 4],
fill=color, outline=color)
# 绘制标签文字
draw.text((label_x + 2, label_y + 2), f"{i+1}: {text}",
fill=(255, 255, 255), font=font)
# 保存结果
if output_path is None:
base_name = os.path.splitext(screenshot_path)[0]
output_path = f"{base_name}_with_boxes.png"
img.save(output_path)
print(f"🎨 带框截图已保存: {output_path}")
return output_path
except Exception as e:
print(f"❌ 绘制失败: {e}")
return None
def load_elements_from_json(json_path):
"""
从JSON文件加载元素数据
"""
try:
with open(json_path, 'r', encoding='utf-8') as f:
elements = json.load(f)
print(f"📂 从 {json_path} 加载了 {len(elements)} 个元素")
return elements
except Exception as e:
print(f"❌ 加载JSON失败: {e}")
return []
def main():
"""
主函数:截图、获取JSON、绘制框
"""
print("🚀 开始截图并绘制元素框...")
# 获取设备列表
try:
devices = u2.device_list()
print(f"📱 可用设备: {devices}")
if devices:
device_id = devices[0] # 使用第一个设备
print(f"使用设备: {device_id}")
else:
device_id = None
print("使用默认设备连接")
except:
device_id = None
print("使用默认设备连接")
# 执行截图和元素提取
screenshot_path, json_path, elements = get_screenshot_and_elements(device_id)
if screenshot_path and elements:
print(f"\n✅ 截图和JSON获取完成!")
print(f"📸 截图文件: {screenshot_path}")
print(f"📝 元素数据: {json_path}")
print(f"🔢 共提取 {len(elements)} 个元素")
# 绘制元素框
output_path = draw_boxes_on_screenshot(screenshot_path, elements)
if output_path:
print(f"\n🎉 任务完成!")
print(f"📸 原截图: {screenshot_path}")
print(f"📝 元素数据: {json_path}")
print(f"🎨 带框截图: {output_path}")
else:
print("❌ 绘制框失败")
else:
print("❌ 截图或元素获取失败")
if __name__ == "__main__":
main()


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!