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 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!