Autojs基础-坐标操作

114 阅读15分钟

1.前言

坐标操作是基于坐标,模拟人的点击、长按、滑动、触摸等操作。虽然这部分内容比较简单,但是这是脚本开发最重要的部分。坐标操作贯穿脚本的整个过程,每个脚本开发软件都会带有这些功能,我这里就不过多介绍。

2.setScreenMetrics

屏幕宽高设置函数,需要传递两个参数,分别为屏幕宽度和屏幕高度,参数类型均为数字,单位均为像素。这个函数一般在多屏幕分辨率场景下使用,用于指定当前坐标操作在哪个分辨率下完成的,当屏幕分辨率改变时,会自动根据当前屏幕分辨率进行校对。比如指定手机宽度为720和高度为1280,点击(200,400)坐标;到了手机宽度为360和高度为640的手机,点击坐标自动转换为(100,200)。通过转换规则会发现,坐标转换会完全按照屏幕比进行一比一转换。

其实,我们在脚本开发过程中,会在固定分辨率下完成脚本,比如我常用的分辨率720*1280。。一般不会有人开发多个分辨率的脚本,虽然坐标操作会自动转换,但是图像处理要做多个分辨率的处理,脚本开发的工作量成倍增加。正常情况下,我们会在固定屏幕分辨率下完成脚本,后面无论是在模拟器还是虚拟机下运行脚本,都采用这个分辨率。这种情况下,根本不需要进行坐标转换,因此这个函数大多数情况下不需要使用。

3.坐标信息

我们平时说的屏幕分辨率为竖屏情况下的宽度和高度的像素值,比如720*1280就是代表竖屏情况下屏幕宽度为720像素,高度为1280像素。为了坐标点击更准确,脚本会以屏幕左上角为原点,以向右为x轴正方向,以向下为y轴正方向,生成一个二维坐标系。下面坐标点击的x,y值都是代表这个坐标系的值,不会再过多介绍。

一般情况下,所有脚本软件在竖屏情况下的横纵坐标设置都是这个情况。但是,在横屏情况下,横纵坐标设置会五花八门,这才是让人头疼的地方。autojs脚本脚本横纵坐标设置,还是按照我上面说的规则,以屏幕左上角为原点,以向右为x轴正方向,以向下为y轴正方向,生成一个二维坐标系。但是横屏情况下,竖屏情况下以宽度为横坐标,横屏情况下以高度为横坐标;竖屏情况下以高度为纵坐标,横屏情况下以宽度为纵坐标。autojs比较好的就是原点还是左上角,并且x,y轴的正方向也没有改变。如果你使用过按键精灵手机助手进行截图,会发现横屏情况下的纵坐标的正方向都会改变,那才是让人头疼的,为了不误解大家,我就不截图按键精灵手机助手坐标系了。默认情况下,使用此横屏坐标系,如果不使用此坐标系时,会进行说明。

其实,脚本开发过程中,我们根本不关心这个坐标是怎么转换的。虽然按键精灵手机助手,横屏转换后,坐标系很难让人理解,但是按键精灵手机助手有自己的截图和选点助手,我们只要保证我们选点和点击位置能够与屏幕对应就可以了,到时候直接复制使用即可,根本不需要关心坐标系问题。

如果你看过其他人讲解的autojs脚本开发教程,他们都会采用各种方式获取屏幕坐标点,这种方式用于讲解脚本还可以,要是用于项目级别的脚本开发怎么办?尤其是图像处理过程中,一个处理就需要那么多点和颜色,通过哪些方式,开发个脚本得浪费都多少时间。可能有小伙伴说,有个别教程上有截图助手,但是那些助手好获取吗?真的好用吗?
当然,没有截图助手,难道就不能开发脚本了吗?当然可以,但是真的很慢,很痛苦。我做了个竖屏的游戏脚本,通过按键精灵手机助手获取点坐标(因为竖屏情况下,两者点坐标是一致的),但是按键精灵手机助手和autojs的颜色表示不一致,我当初还没有找到转换规律。只能想通过按键精灵手机助手先获取需要比对点的信息,然后通过我封装的按键精灵点信息到autojs点信息转换的函数打印需要的信息,这个过程很复杂就不介绍了。但是每个图像处理,我都得先运行代码获取转换信息,然后将信息替换到代码,然后再运行代码检查是否识别到。就是每个图像处理,我都得运行两次autojs代码才行,还得配合按键精灵手机助手使用,速度真的很慢。我比较庆幸的是这个项目是竖屏项目,我如果刚接触是横屏项目,没有理解按键精灵手机助手和autojs脚本之间的坐标转换,我真可能会放弃。

那个游戏很老了,是小时候那种直板机都可以玩的游戏。后来,我去接触横屏游戏,发现这种方式效率越来越低,经过一系列为了提高效率的各种方式,我直接通过html封装了两个转换页面,最终达成直接复制按键精灵生成的点颜色信,转换成自己需要的点颜色信息。后面会介绍坐标转换工具,对于点颜色转换工具在图像处理模块会进行介绍。

4.无障碍操作

1.click

点击屏幕,需要传递两个参数,分别为x坐标和y坐标,参数类型均为数字,点击过程大约150毫秒。

2.longClick

长按屏幕,需要传递两个参数,分别为x坐标和y坐标,参数类型均为数字,长按过程大约600毫秒。

3.press

按住屏幕,需要传递三个参数,分别为x坐标、y坐标和按住时间,参数类型均为数字。这个函数可以完成上面的click和longClick函数的功能,按住时间较少时可以理解为点击,按住时间较长时间是可以理解为长按。一般对于上面两个函数默认操作时间不满意时,可以通过这个函数完成功能。

4.swipe

两点之间滑动屏幕,需要传递5个参数,分别为滑动起始位置的x坐标、滑动起始位置的y坐标、滑动结束位置的x坐标、滑动结束位置的y坐标和滑动时长(单位:毫秒),参数类型均为数字。我自己感觉这个滑动起始位置和结束位置很容易弄反了,每次使用这个函数时,可以自己将手指放在屏幕上试下然后再取点。

5.gesture

一个手指多点滑动屏幕,需要传递两个参数,分别为滑动时长(单位:毫秒)和点数组,参数类型分别为数字和数组。这个函数过程类似屏幕滑动解锁的过程。

gesture(1000, [[30, 296], [454, 350], [127, 553], [489, 599]]);

6.gestures

一个手指多点滑动屏幕,需要至少一个参数,参数类型为数组。传递一个参数时,功能和gesture函数一致,gestures函数可以理解为多个gesture函数同时操作。每个参数数组包含至少三个值,分别代表延迟多久执行、执行时长和第三值以后代表点数组。这个函数我不建议使用,我发现这个函数稳定性不太行。很容易导致应用闪退。建议如果使用多手指滑动,不如执行gesture函数。

gestures([0, 500, [1199, 527], [137, 500]],
    [500, 500, [743, 129], [389, 125]]
);

5.Root操作

1.Tap

使用方式以及作用与无障碍操作的click函数完全一致。但是Tap函数需要在Root权限的基础上执行,效率远低于click函数,一般不会使用。

2.Swipe

使用方式以及作用与无障碍操作的swipe函数完全一致。但是Swipe函数需要在Root权限的基础上执行,效率远低于swipe函数,一般不会使用。

6.RootAutomator操作

1.概况

RootAutomator操作横屏状态下的坐标系与按键精灵手机助手的坐标系完全一致,如果使用此对象进行坐标系操作,就不会涉及坐标转换。但是,RootAutomator操作需要在root环境下完成,目前很多手机已经没有root环境,因此无障碍操作还是我们使用最多的坐标操作。现在是学习情况下,横屏条件下,使用此对象操作坐标的坐标情况如下图:

虽然这个坐标系正方向感觉有点怪,但是按键精灵手机助手的抓抓就是在此环境下完成的,抓取的坐标可以直接使用。如果脚本环境是支持root的情况下,用RootAutomator操作坐标也是不错的选择,最起码不用考虑坐标转换问题了,但是还要配合颜色信息转换工具完成转换,具体使用到此工具时候再进行介绍。但是,哪怕在root环境下,我也会通过无障碍操作坐标,因为无障碍兼容性最好,操作速度也是最快的。

2.构造函数

所有的RootAutomator操作都是通过构造函数获取的对象完成。也就是说,使用RootAutomator操作之前先构造这个对象,然后通过这个对象调用里面的函数。构造函数接受一个对象,对象包含adb和inputDevice两个参数,参数分别代表是否使用adb权限和指定操作的设备,参数类型分别为boolean和字符串类型。虽然这个构造函数可以传递对象信息,但是我们在使用时,不需要进行传递,使用默认配置即可。这个对象参数我也没有很深入的研究,大家记得使用默认即可,因为整个RootAutomator操作一般情况下都不会使用,对于这部分有所了解即可。

let currentObj = new RootAutomator();
getAutojsObjectFunctions(currentObj);

// 获取Autojs对象所有的函数
function getAutojsObjectFunctions(obj) {
    if (obj == null || typeof obj !== 'object') {
        console.log('参数必须是一个对象');
        return;
    }

    // 获取对象自身的所有属性名
    var propertyNames = Object.getOwnPropertyNames(obj);

    // 筛选出函数类型的属性
    var functionNames = propertyNames.filter(function (prop) {
        return typeof obj[prop] === 'function';
    });

    if (functionNames.length === 0) {
        console.log('该对象没有函数属性');
        return;
    }

    // 遍历并打印每个函数的信息
    functionNames.forEach(function (methodName) {

        // 按照指定格式打印
        console.log("函数名: " + methodName + "()");
    });
}

3.exit

退出函数,用于销毁创建的RootAutomator操作对象。如果想使用RootAutomator进行坐标操作,可以想通过构造函数获取操作对象,然后进行一系列操作,然后在脚本最后调用退出函数,销毁操作对象。也就是说,整个脚本过程中,可以通过构造函数只创建一个RootAutomator对象,在脚本最后只通过exit函数销毁一次操作对象。其实,我们真正脚本开发中,我们使用最多的还是无障碍操作,其他坐标操作很少使用。

注意:

如果用于简单的功能测试时,在操作函数调用之后,加个延迟,再调用exit函数。如果不加延迟,会导致直接销毁对象,导致操作函数不生效。这种问题只是会出现在测试过程中,由于exit函数比操作函数快,导致未操作之前销毁了对象。但是,在实际脚本开发过程中,坐标操作和图像处理配合使用,exit函数也就执行一次,不会出现操作不执行的情况,就是脚本最后一个操作注意一下就行,为了不出现问题,可以在exit函数退出之前都加个500毫秒的延迟。

4.tap

点击屏幕,需要传递三个参数,分别为x坐标、y坐标、操作id,参数类型均为数字。这个函数的功能和无障碍的click函数功能类似,RootAutomator对象下的操作函数都是有个操作id,这个id是操作的唯一标识,用于区分不同的操作。后面操作函数的参数操作id功能相同,不会再介绍。

let currentObj = new RootAutomator();
currentObj.tap(280, 540, 1);
sleep(500);
currentObj.exit();

注意:

官方文档中,说操作id可以选填,默认为1,但是我不传递操作id,操作会不执行。我们在单操作过程中,为了保证函数执行,也手动填写一个值为1的操作id。

5.swipe

两点之间滑动屏幕,需要传递6个参数,分别为滑动起始位置的x坐标、滑动起始位置的y坐标、滑动结束位置的x坐标、滑动结束位置的y坐标、滑动时长(单位:毫秒)和操作id,参数类型均为数字。功能和无障碍操作的swipe函数类似。swipe函数传参,可以和官方文档中说明一致,滑动时长和操作id可以不传递。

6.press与longPress

press代表触摸屏幕,需要传递四个参数,分别为x坐标、y坐标、按下时间(单位:毫秒)、操作id,参数类型均为数字。longPress代表长时间触摸屏幕,需要传递三个参数,分别为x坐标、y坐标、操作id。press可以和官方文档中说明一致,操作id可以不传递,默认为1。但是,longPress官方文档说可以传递按下时长,实际上此函数只能传递上述三个参数,最后一个参数操作id可以不传递。这两个函数功能也类似,只是longPress函数不能设置按下时间罢了。

let currentObj = new RootAutomator();
currentObj.press(574, 73, 100);
sleep(1000);
currentObj.exit();

7.touchDown、touchMove和touchUp

touchDown和touchMove分别代表手指按下和手指滑动,均需要传递三个参数,分别为x坐标、y坐标、操作id,操作id可以不传递,默认为1。touchUp代表手指弹起,只需要传递操作id这一个参数,这个参数可以不传递,默认为1。通过这三个函数可以实现点击、触摸、滑动等操作,这三个函数更像是将一个功能分步完成,特别需要注意,按下或者滑动后,调用一下手指弹起函数。

let currentObj = new RootAutomator();
// 模拟点击
currentObj.touchDown(574, 73);
currentObj.touchUp();
sleep(1000);

// 模拟滑动
currentObj.touchDown(116, 756, 2);
currentObj.touchMove(326,748, 2);
currentObj.touchUp(2);

sleep(1000);
currentObj.exit();

7.RootAutomator2操作

在官方第一代API文档中,存在RootAutomator2的相关内容,但是实际上,autojs免费版根本没有RootAutomator2对象。我们使用免费版参考第一代API文档内容能够满足大部分需求,但是第一代API文档中的部分内容与我们autojs免费版有冲突,甚至有些对象或者函数在免费版中根本不存在,这也是制作autojs教程的原因。下面代码证明了RootAutomator对象存在,但是RootAutomator2对象不存在。

if (typeof RootAutomator != "undefined") {
    console.log("存在RootAutomator对象");
} else {
    console.log("不存在RootAutomator对象");
}

if (typeof RootAutomator2 != "undefined") {
    console.log("存在RootAutomator2对象");
} else {
    console.log("不存在RootAutomator2对象");
}

8.总结

对于autojs免费版来说,坐标操作有无障碍和RootAutomator两种方式。竖屏状态下,两者坐标系是一致的。在横屏状态下,无障碍的坐标系利于理解,RootAutomator的坐标系和按键精灵手机助手一致。无障碍的坐标系虽然和截图软件的坐标系会有冲突,但是配合后面的颜色信息转换工具使用,就不存在这个问题。哪怕使用RootAutomator不用转换坐标,但是按键精灵手机助手的颜色信息和autojs的颜色信息有区别,也要通过颜色信息转换工具进行颜色转换。因此,无障碍的坐标系冲突显得不那么重要,哪怕点击操作只需要获取转换后的坐标,也有对应的坐标转换工具。我不推荐RootAutomator的原因是,现在很多环境是不支持Root的,同时RootAutomator速度远没有无障碍快,兼容性也没无障碍好。 特别注意,只有通过个人主页博客或者个人介绍中方式,才能获取源码