本项目旨在提供一个灵活且可靠的移动设备自动化测试框架,支持通过辅助功能定位器(preferred)和基于坐标的输入进行操作。用户可以根据实际需求选择使用不同的定位方式,以实现无缝的自动化流程。
本项目提供了一系列用于操作移动设备的命令,通过这些命令可以模拟各种用户操作,实现移动设备的自动化测试等功能。以下将详细介绍各个命令的使用方法。
文档中未提及安装相关内容,故跳过此章节。
// 示例:使用 mobile_tap_elements 函数依次点击两个元素
var elements = ["element1", "element2"];
mobile_tap_elements(elements, true);
// 组合多种操作示例
const mobileOperations = new MobileOperations();
mobileOperations.addOperation(MobileOperations.OPERATION_TYPE.TAP, { x: 100, y: 200 });
mobileOperations.addOperation(MobileOperations.OPERATION_TYPE.LONG_TAP, { x: 300, y: 400, duration: 1000 });
mobileOperations.execute();
mobile_list_appsbundleId (字符串):应用程序唯一的包/标识符,例如:com.google.android.keep 或 com.apple.mobilenotes。mobile_launch_appbundleId (字符串):应用程序唯一的包/标识符,例如:com.google.android.keep 或 com.apple.mobilenotes。mobile_terminate_apppackageName (字符串):根据应用程序的包/标识符调用 am force stop 或直接终止进程。mobile_get_screen_sizemobile_click_on_screen_at_coordinatesx (数字):X 坐标y (数字):Y 坐标mobile_list_elements_on_screenmobile_element_tapelement (字符串):人类可读的元素描述(例如,“登录按钮”)。ref (字符串):辅助功能/自动化 ID 或从快照中获取的引用。mobile_tapx (数字):X 坐标y (数字):Y 坐标mobile_press_buttonmobile_open_urlurl (字符串):要打开的 URL 地址,例如:https://example.com。mobile_type_texttext (字符串):要输入的文本submit (布尔值):是否在输入后按下回车键mobile_element_swipestartElement (字符串):起始元素的人类可读描述startRef (字符串):起始元素的辅助功能/自动化 IDendElement (字符串):结束元素的人类可读描述endRef (字符串):结束元素的辅助功能/自动化 IDmobile_swipestartX (数字):起始 X 坐标startY (数字):起始 Y 坐标endX (数字):结束 X 坐标endY (数字):结束 Y 坐标mobile_press_and_holdx (数字):X 坐标y (数字):Y 坐标duration (数字):长按的持续时间(以毫秒为单位)mobile_drag_and_dropfromX (数字):拖动起点的 X 坐标fromY (数字):拖动起点的 Y 坐标toX (数字):拖动终点的 X 坐标toY (数字):拖动终点的 Y 坐标mobile_scrolldirection (字符串):滚动方向,可选值为:up, down, left, rightmobile_get_textelementRef (字符串):元素的辅助功能/自动化 IDmobile_set_textelementRef (字符串):元素的辅助功能/自动化 IDtext (字符串):要设置的文本内容mobile_clear_textelementRef (字符串):输入框元素的辅助功能/自动化 IDmobile_click_element_by_texttext (字符串):元素显示的文本内容partialMatch (布尔值, 可选):是否允许部分匹配,默认为 falsemobile_click_element_by_content_descriptioncontentDescription (字符串):元素的内容描述partialMatch (布尔值, 可选):是否允许部分匹配,默认为 falsemobile_wait_for_elementelementRef (字符串):元素的辅助功能/自动化 IDtimeout (数字, 可选):等待超时时间,以毫秒为单位,默认为 30000mobile_take_screenshotfilename (字符串, 可选):保存的文件名,默认自动生成。mobile_device_timemobile_set_volumevolumeLevel (数字):音量级别,取值范围为 0 到 1.0mobile_toggle_airplane_modemobile_check_wifi_connectionssid (字符串, 可选):要检查的 Wi-Fi SSIDtimeout (数字, 可选):等待超时时间,以秒为单位,默认为 30mobile_connect_to_wifissid (字符串):要连接的 Wi-Fi SSIDpassword (字符串, 可选):Wi-Fi 密码mobile_disconnect_WIFImobile_check_network_connectionnetworkType (字符串, 可选):要检查的网络类型,可选值为:wifi, mobilemobile_set_geolocationlatitude (数字):纬度longitude (数字):经度altitude (数字, 可选):海拔,默认为 0mobile_unset_geolocationmobile_back_to_home_screenmobile_launch_apppackageName (字符串):应用的包名activityName (字符串, 可选):要启动的 Activity 名称,默认为应用默认启动页面mobile_close_apppackageName (字符串):应用的包名mobile_clear_app_datapackageName (字符串):应用的包名mobile_install_apkapkPath (字符串):APK 文件的路径waitTime (数字, 可选):安装完成后等待的时间,以秒为单位,默认为 5mobile_uninstall_apkpackageName (字符串):应用的包名mobile_push_filelocalFilePath (字符串):本地文件路径remoteFileName (字符串, 可选):设备上的文件名称,默认与本地文件名相同mobile_pull_fileremoteFileName (字符串):设备上的文件路径localSavePath (字符串, 可选):本地保存路径,默认为当前工作目录mobile_logcat_clearmobile_logcat_dumpfilename (字符串, 可选):保存的日志文件名,默认自动生成。mobile_input_textelementRef (字符串):输入框元素的辅助功能/自动化 IDtext (字符串):要输入的文本内容mobile_input_numberelementRef (字符串):数字输入框元素的辅助功能/自动化 IDnumberValue (数字):要输入的数值mobile_switch_to_webviewwebViewIndex (数字, 可选):要切换的 WebView 索引,默认为第一个 WebViewmobile_switch_to_nativemobile_get_current_contextresult (字符串):当前上下文的类型,返回值为:NATIVE, WEBVIEWmobile_wait_for_element_textelementRef (字符串):元素的辅助功能/自动化 IDexpectedText (字符串):期望的文本内容timeout (数字, 可选):等待超时时间,以毫秒为单位,默认为 30000mobile_compare_element_textelementRef (字符串):元素的辅助功能/自动化 IDexpectedText (字符串):期望的文本内容ignoreCase (布尔值, 可选):是否忽略大小写,默认为 falsemobile_is_element_presentelementRef (字符串):元素的辅助功能/自动化 IDresult (布尔值):存在返回 true,否则返回 falsemobile_is_element_enabledelementRef (字符串):元素的辅助功能/自动化 IDresult (布尔值):启用返回 true,否则返回 falsemobile_is_element_selectedelementRef (字符串):元素的辅助功能/自动化 IDresult (布尔值):被选中返回 true,否则返回 falsemobile_is_element_displayedelementRef (字符串):元素的辅助功能/自动化 IDresult (布尔值):可见返回 true,否则返回 falsemobile_element_attributeelementRef (字符串):元素的辅助功能/自动化 IDattributeName (字符串):要获取的属性名称result (字符串):属性对应的值mobile_element_textelementRef (字符串):元素的辅助功能/自动化 IDresult (字符串):文本内容mobile_set_valueelementRef (字符串):输入框元素的辅助功能/自动化 IDvalue (字符串):要设置的文本内容mobile_press_elementelementRef (字符串):元素的辅助功能/自动化 IDtimes (数字, 可选):点击次数,默认为 1mobile_long_press_elementelementRef (字符串):元素的辅助功能/自动化 IDduration (数字, 可选):长按的时间,以毫秒为单位,默认为 500mobile_swipe_elementelementRef (字符串):元素的辅助功能/自动化 IDdirection (字符串):滑动方向,可选值为:LEFT, RIGHTdistance (数字, 可选):滑动的距离,默认为元素宽度的一半mobile_drag_elementelementRef (字符串):元素的辅助功能/自动化 IDtargetElementRef (字符串, 可选):要拖拽到的目标元素的辅助功能/自动化 ID,默认为 null,表示拖拽到屏幕中心位置duration (数字, 可选):拖拽操作的时间,以毫秒为单位,默认为 500mobile_scroll_elementelementRef (字符串):元素的辅助功能/自动化 IDdirection (字符串):滚动方向,可选值为:UP, DOWN, LEFT, RIGHTsteps (数字, 可选):滚动的步数,默认为 1mobile_pinch_elementelementRef (字符串):元素的辅助功能/自动化 IDscaleFactor (数字, 可选):捏合的比例因子,范围在 (0,1) 之间,默认为 0.5duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_zoom_elementelementRef (字符串):元素的辅助功能/自动化 IDscaleFactor (数字, 可选):缩放的比例因子,范围在 (0,1) 或 (1, infinity) 之间,默认为 2duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_rotate_elementelementRef (字符串):元素的辅助功能/自动化 IDdegrees (数字, 可选):旋转的角度,范围在 -180 到 180 之间,默认为 90duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_tap_coordinatesx (数字):点击的 x 坐标y (数字):点击的 y 坐标mobile_tap_elementselements (数组):元素的辅助功能/自动化 ID 数组simultaneous (布尔值, 可选):是否同时点击,默认为 falsemobile_long_tap_coordinatesx (数字):长按的 x 坐标y (数字):长按的 y 坐标duration (数字, 可选):长按的时间,以毫秒为单位,默认为 500mobile_swipe_coordinatesstartX (数字):起始点的 x 坐标startY (数字):起始点的 y 坐标endX (数字):终止点的 x 坐标endY (数字):终止点的 y 坐标duration (数字, 可选):滑动操作的时间,以毫秒为单位,默认为 500mobile_swipe_elementselements (数组):元素的辅助功能/自动化 ID 数组direction (字符串, 可选):滑动方向,默认为 RIGHTsimultaneous (布尔值, 可选):是否同时滑动,默认为 falsemobile_drag_coordinatesstartX (数字):拖拽起点的 x 坐标startY (数字):拖拽起点的 y 坐标endX (数字):拖拽终点的 x 坐标endY (数字):拖拽终点的 y 坐标duration (数字, 可选):拖拽操作的时间,以毫秒为单位,默认为 500mobile_drag_elementsstartElements (数组):起始点的元素辅助功能/自动化 ID 数组endElements (数组):终止点的元素辅助功能/自动化 ID 数组simultaneous (布尔值, 可选):是否同时拖拽,默认为 falsemobile_pinch_coordinatesstartX (数字):起始点的 x 坐标startY (数字):起始点的 y 坐标endX (数字):终止点的 x 坐标endY (数字):终止点的 y 坐标scaleFactor (数字, 可选):缩放比例,默认为 0.5duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_pinch_elementselements (数组):元素的辅助功能/自动化 ID 数组simultaneous (布尔值, 可选):是否同时捏,默认为 falsemobile_zoom_coordinatesx (数字):缩放的 x 坐标y (数字):缩放的 y 坐标scaleFactor (数字, 可选):缩放比例,默认为 2duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_zoom_elementselements (数组):元素的辅助功能/自动化 ID 数组simultaneous (布尔值, 可选):是否同时缩放,默认为 falsemobile_rotate_coordinatesx (数字):旋转的 x 坐标y (数字):旋转的 y 坐标degrees (数字, 可选):旋转角度,默认为 90duration (数字, 可选):操作的时间,以毫秒为单位,默认为 500mobile_rotate_elementselements (数组):元素的辅助功能/自动化 ID 数组degrees (数字, 可选):旋转角度,默认为 90simultaneous (布尔值, 可选):是否同时旋转,默认为 false// mobile_operations.js
// 定义操作类型常量
const OPERATION_TYPE = {
TAP: 'tap',
LONG_TAP: 'longTap',
SWIPE: 'swipe',
DRAG: 'drag',
PINCH: 'pinch',
ZOOM: 'zoom',
ROTATE: 'rotate'
};
// 操作执行器
class MobileOperations {
constructor() {
this.operations = [];
}
// 添加操作
addOperation(type, params) {
this.operations.push({ type, params });
return this;
}
// 执行所有操作
execute(simultaneous = false) {
if (simultaneous) {
// 同时执行所有操作
this.operations.forEach(op => this.executeOperation(op.type, op.params));
} else {
// 顺序执行所有操作
this.operations.forEach(op => this.executeOperation(op.type, op.params));
}
return this;
}
// 执行单个操作
executeOperation(type, params) {
switch (type) {
case OPERATION_TYPE.TAP:
this.mobile_tap(params);
break;
case OPERATION_TYPE.LONG_TAP:
this.mobile_long_tap(params);
break;
case OPERATION_TYPE.SWIPE:
this.mobile_swipe(params);
break;
case OPERATION_TYPE.DRAG:
this.mobile_drag(params);
break;
case OPERATION_TYPE.PINCH:
this.mobile_pinch(params);
break;
case OPERATION_TYPE.ZOOM:
this.mobile_zoom(params);
break;
case OPERATION_TYPE.ROTATE:
this.mobile_rotate(params);
break;
default:
throw new Error('未知的操作类型');
}
}
// 点击操作
mobile_tap(params) {
const { x, y } = params;
// 在屏幕上点击
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 点击`);
}
// 长按操作
mobile_long_tap(params) {
const { x, y, duration = 500 } = params;
// 在屏幕上长按指定时长
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 长按 ${duration} 毫秒`);
}
// 滑动操作
mobile_swipe(params) {
const { start, end, duration = 500 } = params;
// 从起点滑动到终点
if (typeof start.x !== 'number' || typeof start.y !== 'number') {
throw new Error('start 必须有 x 和 y 坐标');
}
if (typeof end.x !== 'number' || typeof end.y !== 'number') {
throw new Error('end 必须有 x 和 y 坐标');
}
console.log(`从 (${start.x}, ${start.y}) 滑动到 (${end.x}, ${end.y})`);
}
// 拖拽操作
mobile_drag(params) {
const { start, end, duration = 500 } = params;
// 从起点拖拽到终点
if (typeof start.x !== 'number' || typeof start.y !== 'number') {
throw new Error('start 必须有 x 和 y 坐标');
}
if (typeof end.x !== 'number' || typeof end.y !== 'number') {
throw new Error('end 必须有 x 和 y 坐标');
}
console.log(`从 (${start.x}, ${start.y}) 拖拽到 (${end.x}, ${end.y})`);
}
// 捏合操作
mobile_pinch(params) {
const { points, scale = 0.5, duration = 500 } = params;
// 对指定点进行捏合操作
if (!Array.isArray(points) || points.length !== 2) {
throw new Error('points 必须是两个点的数组');
}
console.log(`对点 ${JSON.stringify(points)} 进行捏合,缩放比例为 ${scale}`);
}
// 缩放操作
mobile_zoom(params) {
const { x, y, scale = 2, duration = 500 } = params;
// 在指定位置进行缩放
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 进行缩放,比例为 ${scale}`);
}
// 旋转操作
mobile_rotate(params) {
const { x, y, degrees = 90, duration = 500 } = params;
// 在指定位置进行旋转
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 进行旋转,角度为 ${degrees} 度`);
}
// 组合操作示例
static exampleOperations() {
const mo = new MobileOperations();
// 点击操作
mo.addOperation(OPERATION_TYPE.TAP, { x: 100, y: 200 });
// 长按操作
mo.addOperation(OPERATION_TYPE.LONG_TAP, { x: 300, y: 400, duration: 1000 });
// 滑动操作
mo.addOperation(OPERATION_TYPE.SWIPE, {
start: { x: 50, y: 50 },
end: { x: 250, y: 250 }
});
// 拖拽操作
mo.addOperation(OPERATION_TYPE.DRAG, {
start: { x: 100, y: 100 },
end: { x: 300, y: 300 }
});
return mo;
}
// 执行示例操作
static executeExample() {
const operations = this.exampleOperations();
operations.execute();
}
}
// 使用示例
const mobileOperations = new MobileOperations();
mobileOperations.addOperation(MobileOperations.OPERATION_TYPE.TAP, { x: 100, y: 200 });
mobileOperations.addOperation(MobileOperations.OPERATION_TYPE.LONG_TAP, { x: 300, y: 400, duration: 1000 });
mobileOperations.execute();
class MobileOperations {
constructor() {
this.operations = [];
}
addOperation(type, params) {
if (!this[type]) {
throw new Error('未知的操作类型');
}
this.operations.push({ type, params });
return this;
}
execute() {
for (const op of this.operations) {
this[op.type](op.params);
}
return this;
}
// 点击操作
mobile_tap(params) {
const { x, y } = params;
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 点击`);
}
// 长按操作
mobile_long_tap(params) {
const { x, y, duration = 500 } = params;
if (typeof x !== 'number' || typeof y !== 'number') {
throw new Error('x 和 y 必须是数字');
}
console.log(`在坐标 (${x}, ${y}) 长按 ${duration} 毫秒`);
}
// 滑动操作
mobile_swipe(params) {
const { start, end, duration = 500 } = params;
if (typeof start.x !== 'number' || typeof start.y !== 'number') {
throw new Error('start 必须有 x 和 y 坐标');
}
if (typeof end.x !== 'number' || typeof end.y !== 'number') {
throw new Error('end 必须有 x 和 y 坐标');
}
console.log(`从 (${start.x}, ${start.y}) 滑动到 (${end.x}, ${end.y})`);
}
// 拖拽操作
mobile_drag(params) {
const { start, end, duration = 500 } = params;
if (typeof start.x !== 'number' || typeof start.y !== 'number') {
throw new Error('start 必须有 x 和 y 坐标');
}
if (typeof end.x !== 'number' || typeof end.y !== 'number') {
throw new Error('end 必须有 x 和 y 坐标');
}
console.log(`从 (${start.x}, ${start.y}) 拖拽到 (${end.x}, ${end.y})`);
}
// 捏合操作
mobile_pinch(params) {
const { points, scale = 0.5, duration = 500 } = params;
if (!Array.isArray(points)) {
throw new Error('points 必须是数组');
}
console.log(`执行捏合操作,点为 ${JSON.stringify(points)},缩放比例为 ${scale}`);
}
// 旋转操作
mobile_rotate(params) {
const { center, startAngle, endAngle, duration = 500 } = params;
if (typeof center.x !== 'number' || typeof center.y !== 'number') {
throw new Error('center 必须有 x 和 y 坐标');
}
console.log(`以点 (${center.x}, ${center.y}) 为中心,从 ${startAngle} 度旋转到 ${endAngle} 度`);
}
// 执行示例操作
static example() {
const operations = new MobileOperations()
.addOperation('mobile_tap', { x: 100, y: 200 })
.addOperation('mobile_long_tap', { x: 300, y: 400, duration: 1000 })
.addOperation('mobile_swipe', {
start: { x: 50, y: 50 },
end: { x: 250, y: 250 }
})
.addOperation('mobile_drag', {
start: { x: 100, y: 100 },
end: { x: 300, y: 300 }
})
.addOperation('mobile_pinch', {
points: [{ x: 150, y: 150 }, { x: 250, y: 250 }],
scale: 0.8
})
.addOperation('mobile_rotate', {
center: { x: 200, y: 200 },
startAngle: 0,
endAngle: 360
});
operations.execute();
}
}
// 使用示例
MobileOperations.example();
移动设备的交互操作通常包括点击、长按、滑动、拖拽、捏合和旋转等基本操作。为了实现这些操作,可以将每一种操作封装成一个函数,并允许它们组合在一起执行。
这个解决方案中定义了一个 MobileOperations 类,它包含各种移动设备操作的方法(如点击、长按等),每个方法对应一种交互类型。通过使用 addOperation 方法可以将多种操作添加到操作队列中,最后调用 execute() 方法来依次执行这些操作。
这种方法允许用户灵活地组合不同的操作,并且每个操作独立实现,便于扩展和维护。
文档中未提及技术细节相关内容,故跳过此章节。
文档中未提及许可证相关内容,故跳过此章节。