以下内容在 夜神模拟器 上进行。
一、应用场景
一些针对手势的操作,比如滑动、长按、拖动等。可以将这些基本手势组合成一个相对复杂的手势。
二、使用步骤
创建触摸输入设备(模拟手指操作)
touch_input = PointerInput(interaction.POINTER_TOUCH, "touch")
创建动作构建器
action_builder = ActionBuilder(driver, mouse=touch_input)
构建动作
用perform执行完整动作链
action_builder.perform()
三、PointerActions方法详解
按住Ctrl+左键点击pointer_action
,再从跳转文件Ctrl+左键点击PointerActions
,跳转PointerActions类查看其方法详细内容
作用:将指针(如手指)移动到屏幕指定坐标(x, y),x:目标位置的 X 坐标(相对于屏幕左上角,单位像素)
pointer_down(
self,
button=MouseButton.LEFT,
width=None,
height=None,
pressure=None,
tangential_pressure=None,
tilt_x=None,
tilt_y=None,
twist=None,
altitude_angle=None,
azimuth_angle=None,
)
对于大多数普通场景(如点击、滑动),无需复杂参数,仅需指定基础动作即可:
action.pointer_action.pointer_down()
pointer_up(button=MouseButton.LEFT)
支持基于元素或坐标的移动,还可通过参数控制移动过程中的触摸细节(如压力、角度等):
def move_to(
self,
element,
x=0,
y=0,
width=None,
height=None,
pressure=None,
tangential_pressure=None,
tilt_x=None,
tilt_y=None,
twist=None,
altitude_angle=None,
azimuth_angle=None,
)
基于元素的移动
以元素为基准,通过 x/y 设定相对偏移(适合元素位置动态变化的场景):# 移动到元素的右上角(元素左上角 + 宽偏移,高0) element = driver.find_element('id', 'target_btn') action.pointer_action.move_to( element=element, x=element.size['width'], # 相对元素左上角X偏移(等于元素宽度→右上角) y=0 # 相对元素左上角Y偏移0 )
基于绝对坐标的移动
action.pointer_action.move_to(x=500, y=300)
结合按下 / 抬起实现滑动
移动过程中保持按下状态,实现滑动效果:# 从元素A滑动到元素B element_a = driver.find_element('id', 'start_point') element_b = driver.find_element('id', 'end_point') # 移动到A→按下→移动到B→抬起(完成滑动) action.pointer_action.move_to(element=element_a) action.pointer_action.pointer_down() # 按下(开始滑动) action.pointer_action.move_to(element=element_b) # 滑动到B action.pointer_action.pointer_up() # 抬起(结束滑动) action.perform()
基于相对当前位置移动指针设备,move_by()
是实现连续、精细手势的核心方法,尤其适合需要模拟人手自然滑动的场景(如滚动列表、拖拽控件等):
def move_by(
self,
x,
y,
width=None,
height=None,
pressure=None,
tangential_pressure=None,
tilt_x=None,
tilt_y=None,
twist=None,
altitude_angle=None,
azimuth_angle=None,
)
- 基础相对移动
# 假设指针当前在(100, 200)位置
action.pointer_action.move_by(x=200, y=100) # 向右移动200px,向下移动100px→新位置(300, 300)
- 按下并连续滑动
按下并连续滑动(分两步向上移动):
action.pointer_action.pointer_down() # 按下(开始滑动)
action.pointer_action.move_by(x=0, y=-300) # 第一步:向上移动300px(y为负)
action.pointer_action.move_by(x=0, y=-300) # 第二步:再向上移动300px
action.pointer_action.pointer_up() # 抬起(结束滑动)
def move_to_location(
self,
x,
y,
width=None,
height=None,
pressure=None,
tangential_pressure=None,
tilt_x=None,
tilt_y=None,
twist=None,
altitude_angle=None,
azimuth_angle=None,
)
示例:
# 移动到屏幕(300, 500)位置并点击
action.pointer_action.move_to_location(x=300, y=500) # 直接定位到绝对坐标
直接对元素或指定坐标位置执行点击:
action.pointer_action.click(element) # 直接点击元素
若未传入 element
,需先通过 move_to_location()
定位到坐标,再调用 click()
。
模拟上下文点击(通常指鼠标右键点击),主要用于触发元素的上下文菜单(如桌面端网页或应用中右键点击元素弹出的菜单)。在移动设备上,此方法通常等效于长按操作(因为移动设备无鼠标右键,长按是触发上下文菜单的常见方式)。
常用于拖拽、长按触发菜单等需要持续按压的场景:
# 拖拽流程:按住→移动→抬起
action.pointer_action.click_and_hold(element=app_icon) # 按住图标
action.pointer_action.move_by(x=200, y=300) # 向右下方移动
action.pointer_action.release() # 抬起(释放图标)
用于结束之前通过 click_and_hold()
、pointer_down()
等方法开始的 “按下” 状态,与 pointer_up
功能基本一致。
double_click(el可选)
,若无element,则需先定位到目标坐标,再执行双击:
# 定位图片元素并双击(如放大图片)
image = driver.find_element('xpath', '//android.widget.ImageView[@index="0"]')
action.pointer_action.double_click(element=image) # 双击图片
duration
单位为秒,浮点型。
在动作链中插入 pause()
后,Appium 会在执行到该步骤时暂停指定时长,再继续执行后续动作。主要用于:
- 模拟长按(按下后暂停一段时间再抬起)。
- 等待前一个动作生效(如点击按钮后等待页面加载)。
- 控制手势速度(如滑动过程中减速)。
示例:
# 分步滑动(每步移动+暂停)
action.pointer_action.move_by(x=0, y=-200) # 第一步上滑
action.pointer_action.pause(0.3) # 暂停0.3秒
action.pointer_action.move_by(x=0, y=-200) # 第二步上滑
四、单点触控案例
代码执行前准备
- 命令行启动appium服务(版本2.19.0):
appium --address 127.0.0.1 --log-level debug --use-drivers uiautomator2
- 模拟器打开,命令行adb devices显示设备已连接
1、点击/长按wifi设置
#!/usr/bin/env python
# encoding: utf-8
'''
@Author : 草木零
@Software: PyCharm
@File : class03_actionBuilder01.py
@Time : 2025/7/28 17:04
@desc : 运行多种方法进行 点击/长按
'''
# 案例1:设置里点击wlan
from time import sleep
from appium import webdriver
from appium.options.android import UiAutomator2Options # 导入 Android 选项类
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.common.actions import interaction
# 手机/模拟器,配置信息
desired_caps = {
"platformName": "Android",
"platformVersion": "7.1.2",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.android.settings",
# 获取包名、界面名:adb shell dumpsys window|findstr mCurrentFocus
"appActivity": "com.android.settings.Settings",
"noReset": False
}
# 显式传入 options 参数(适用于必须使用高版本 Selenium 的场景)
# 将 desired_caps 转换为 Options 实例
options = UiAutomator2Options().load_capabilities(desired_caps)
# 传入 options 参数
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
options=options # 必须传入 options,替代原来的 desired_capabilities
)
# 获取WLAN元素
wlanEl = driver.find_element('xpath', '//*[@text="WLAN"] ')
# 创建触摸输入设备(模拟手指操作)
touch_input = PointerInput(interaction.POINTER_TOUCH, "touch")
# 创建动作构建器
action_builder = ActionBuilder(driver, mouse=touch_input)
# 例子1:为展示多一点操作搞的复杂示例
# 获取元素中心点坐标
# 元素x轴中心点坐标=元素左上角位置坐标x+元素尺寸宽度的一半
x = wlanEl.location['x'] + wlanEl.size['width'] // 2
y = wlanEl.location['y'] + wlanEl.size['height'] // 2
# 执行点击动作(移动→按下→抬起)
action_builder.pointer_action.move_to_location(x, y) #移动
action_builder.pointer_action.pointer_down() # 左键点击
action_builder.pointer_action.release() #释放鼠标
# 例2:直接一步click点击即可
# action_builder.pointer_action.click(wlanEl) #例1那些操作只用这一步可完成点击效果
# 例3:长按:按下(pointer_down或者click_and_hold)+暂停+抬起
# action_builder.pointer_action.click_and_hold(wlanEl) #点击并按住
# action_builder.pointer_action.pause(2) # 暂停2s
# action_builder.pointer_action.pointer_up() #抬起
# 执行完整动作链
action_builder.perform()
driver.quit()
2、滑屏解锁
位置:模拟器——设置—安全—设置屏幕锁定——图案
过程:使用了WEditor找元素位置,如果用Android UIAutomator2模式,和appium不要同时开启,用Android adb可以和appium同时开启
代码:
#!/usr/bin/env python
# encoding: utf-8
'''
@Author : 草木零
@Software: PyCharm
@File : class03_actionBuilder02.py
@Time : 2025/7/29 11:28
@desc : 手机屏幕图案解锁
'''
from time import sleep
from appium import webdriver
from appium.options.android import UiAutomator2Options # 导入 Android 选项类
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.common.actions import interaction
# 手机/模拟器,配置信息
desired_caps = {
"platformName": "Android",
"platformVersion": "7.1.2",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.android.settings",
# 获取包名、界面名:adb shell dumpsys window|findstr mCurrentFocus
"appActivity": "com.android.settings.ChooseLockPattern",
"noReset": False
}
# 显式传入 options 参数(适用于必须使用高版本 Selenium 的场景)
# 将 desired_caps 转换为 Options 实例
options = UiAutomator2Options().load_capabilities(desired_caps)
# 传入 options 参数
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
options=options # 必须传入 options,替代原来的 desired_capabilities
)
# 创建触摸输入设备(模拟手指操作)
touch_input = PointerInput(interaction.POINTER_TOUCH, "touch")
# 创建动作构建器
action_builder = ActionBuilder(driver, mouse=touch_input)
# 桌面图案解锁
window_size = driver.get_window_size() #返回dict格式的当前窗口屏幕尺寸
width = window_size['width'] # 获取宽度
height = window_size['height'] # 获取高度
# 各落点位置
startX = width*0.2
startY = height*0.47
midX = width*0.2
midY = height*0.8
endX = width*0.8
endY = height*0.8
action_builder.pointer_action.move_to_location(startX, startY) #移动至起点位置
action_builder.pointer_action.pointer_down() # 按下
sleep(0.5) # 按下后短暂停留
action_builder.pointer_action.move_to_location(midX, midY) # 滑动到中间位置
sleep(0.5)
action_builder.pointer_action.move_to_location(endX, endY) # 滑动到终点
sleep(0.5) # 滑动过程
action_builder.pointer_action.pointer_up() # 抬起
# 执行完整动作链
action_builder.perform()
sleep(3)
driver.quit()
效果: