移动端自动化 AutoJS 快速入门指南

Posted AirPython

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移动端自动化 AutoJS 快速入门指南相关的知识,希望对你有一定的参考价值。

1. 前言

大家好,我是安果!

之前写过很多 App 端自动化的文章,大都基于 Appium、Airtest、无障碍服务等技术来实现的

其中,Appium 和 Airtest 编写的自动化脚本都依赖于 PC 端运行,没有办法直接运行在移动端;无障碍服务需要单独创建一个 android 项目,没有完整的使用文档,使用起来有一定的门槛

从本篇文章开始,介绍一款可以直接运行在移动端的自动化工具:AutoJS

2. AutoJS 介绍

AutoJS 类似于按键精灵,它是 Android 平台上的一款自动化工具,它通过编写 javascript 脚本,结合系统的「 无障碍服务 」对 App 进行自动化操作

官方文档:https://pro.autojs.org/docs/#/zh-cn/

它的优势包含:

  • 使用 JS 编写脚本,代码可读性强

  • 脚本文件体积小,可以打包成 APK 直接安装

  • 拥有丰富的 UI 组件用于构建 GUI 界面

  • 非 Root 设备也能完成自动化操作,可以摆脱 PC 直接运行

  • 提供多种元素定位方式,可以适配各种机型

  • 官方文档非常详细,学习成本低

3. 准备

AutoJS 拥有多个版本,其中最常用的两个版本分别是:Auto.js Pro、Auto.js 4.1.1 Beta

PS:由于某些原因,AutoJS 作者现在只对 Auto.js Pro 版本进行维护,并且 Auto.js Pro 对部分主流 App 进行了限制

原因:https://pro.autojs.org/faq

后面的文章都是以 Auto.js 4.1.1 Beta 为例进行讲解( 文末有提供下载方式 )

首先,下载 VS Code 软件和 2 个插件

2 个插件包含:

  • Auto.js-VSCodeExt

  • Auto.js-VSCodeExt-Fixed

其中,Auto.js-VSCodeExt-Fixed 对插件 Auto.js-VSCodeExt 进行了部分优化,更加方便我们调试脚本

然后,使用 VS Code 快捷键「 Ctrl/Command + Shift + P 」,选择「 Auto.js:Start Server 」开启 AutoJS 服务

接着,在真机或模拟器安装 AutoJS 应用及 AutoJS 打包工具应用

PS:如果使用模拟器,推荐使用网易 MuMu 或雷电模拟器

打开 AutoJS 应用,首次进入应用关闭更新提示对话框,并按照指引开启「 无障碍服务 」

在软件主界面,点击左上角滑出侧边栏,依次打开无障碍服务、前台服务、悬浮窗

前台服务用于提升服务的存活率,防止服务被回收掉

悬浮窗会悬浮在任意界面之上,提供一些快捷功能操作,具体包含:

  • 文件项目列表

    会展示示例代码及自己编写的脚本、文件夹,可以快速完成脚本编辑、运行、定时任务、打包等操作

  • 脚本录制

    录制脚本,仅适用于 Root 后的设备,由于它基于坐标点,适配性不强,所以很少使用

  • 元素控件定位

    针对当前界面进行布局控件分析、布局层次分析

  • 关闭正在执行的脚本

    一键停止所有正在执行的脚本任务

  • 更多设置

    可以快速进入到「无障碍服务」页面、查看当前应用包名及 Activity 名称等

最后,选中软件侧边栏中的「 连接电脑 」这一项,在对话框中输入 PC 的 ip 地址

PS:AutoJS 连接电脑时如果没有报错,VS Code 通知栏和 OUTPUT 会展示设备连接成功的消息

4. 实战一下

在完成上面的准备工作后,我们就可以在 VS Code 中使用 JS 编写自动化脚本了

这里以自动刷抖音短视频为例

首先,使用「 auto.waitFor() 」确保无障碍服务开启成功

然后,使用 launchApp + 应用名称,快速启动抖音 App

接着使用界面元素内容 + waitFor() 方法等待元素出现,代表界面加载完成

最后,使用 Root + Swipe + 坐标点模拟界面滑动

PS:这里为了方便,直接使用 Root 设备的 API 方法,如果是非 Root 设备,可以采用官方提供的滑动 API 或控件中心坐标点击事件来实现

完整代码如下:

auto.waitFor()

//打开抖音App
var appName = "抖音";
(appName);

//等待进入主界面成功
text("首页").waitFor();

toast("准备开始滑动")

//滑动(Root+坐标点)
while (true) {
    Swipe(200, 1000, 210, 400, 500);
    //休息5s钟
    sleep(5000);
    toast("继续滑动。。。")
}

5. 最后

本篇文章介绍了 AutoJS 最基础的使用步骤,并通过一个简单的实例讲解其用法

文中提到的软件我已经上传到后台,回复关键字「 autojs 」即可以获取

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

推荐阅读
Postman 如何调试加密接口?

5 分钟,使用内网穿透快速实现远程桌面

聊聊 Jmeter 如何并发执行 Python 脚本

聊聊 PC 端自动化最佳方案 - Pywinauto

聊聊 PC 端自动化最佳方案 - WinAppDriver

分享 Python 自动化及爬虫、数据分析实战干货,欢迎关注。

移动端自动测试工具 Appium 快速入门

一、前言

今天简单介绍 移动端 UI 自动测试工具 Appium。

二、Appium 概述

Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用。“移动原生应用”是指那些用 iOS SDK 或者 Android SDK 写的应用。所谓的“移动web 应用”是指使用移动浏览器访问的应用(Appium 支持 iOS 上的 Safari 和 Android 上的 Chrome)。所谓的“混合应用”是指原生代码封装网页视图——原生代码和 web 内容交互。Appium 既能在 window 安装也能在 Mac 上安装,但是 window 上只能跑安卓设备,Mac 上能跑安卓与 IOS 两个设备。

Guihub:You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript (Node), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries.

源码地址:https://github.com/appium/appium

1、架构图

2、UI 自动化收益

任何 UI 自动化测试都不能完部替代人工测试,收益率高不高看部门怎么使用任何工具使用都是两方看怎么使用,如果有重复的工作每次需要人工去回归,建议使用自动化去回归,部门大家都用自动使用,会让大家的心信提高因为每次都机会使用自己写的脚本去验证自己重复工作。

脚本维护成本真的高吗?大家都说成本高,自己是否真的维护过,写过脚本?如果没有写过,没有维护过,没有发言权。只有自己用了才知道是否高。

三、环境安装

1、桌面版本安装

打开下面链接选择版本为exe进行下载:

下载安装后:

点击启动:

2、DOS命令安装


安装JDK

下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html

配置环境变量:

JAVA_HOME:

JAVA_HOME=C:\\Program Files (x86)\\Java\\jdk1.8.0_181
%JAVA_HOME%\\bin;%JAVA_HOME%\\jre\\bin;
CLASSPATH:
.;%JAVA_HOME%\\lib;%JAVA_HOME%\\lib\\tools.jar

Java 验证:

java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) Client VM (build 25.181-b13, mixed mode, sharing)

3、安装SDK

下载地址:

配置环境变量:

ANDROID_HOME
C:\\Program Files (x86)\\android-sdk-windows
Path:
;%ANDROID_HOME%\\tools;%ANDROID_HOME%\\platform-tools
## 下载 node
http://nodejs.cn/download/
## 安装 appium
npm install -g appium

## 如果上面下载比较慢可以使用如下命名
## cnpm 安装
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g appium --no-cache
cnpm i appium-doctor
appium -v

安装验证环境命令:appium-doctor

执行命令验证是否成功:

Appium 版本检查与运行显示:

注意:如果上面环境没有配置,请自己搜索解决。

四、常用操作方法

  • 点击:click()
  • 输入:
sendKeys(CharSequence... keysToSend);
  • 清除:clear()
  • 长按:
     /**
     * 购物车商品图片
     * 长按
     * @param driver
     */
     
    public void cartSingleProductImage(AndroidDriver<AndroidElement> driver, String coordinate) {
        WaitUtil.waitWebElement(driver, getByLocator.getLocatorApp(coordinate), "长按购物车商品图片-弹出收藏与删除浮层");
        element = driver.findElement(getByLocator.getLocatorApp(coordinate));

        int x = element.getLocation().getX();
        int y = element.getLocation().getY();
        TouchAction action = new TouchAction(driver);
        //长按
        action.longPress(PointOption.point(x, y)).release().perform();}
  • 滑动:
       WebElement webElement = null;
        try {
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            webElement = driver.findElementByAndroidUIAutomator(
                    "new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text(\\"See more details\\"))");
        } catch (Exception e) {
            e.printStackTrace();
        }
  • 上下左右滑动,最简单的下滑命令行:(uuid 表示手机设备号)
adb -s " + uuid + " shell input touchscreen swipe 400 800 400 400
     /**
         * 滑动方法
         *
         * @param driver
         * @param direction up、down、left、right
         */

        static Duration duration = Duration.ofSeconds(1);
        public static void swipe(AndroidDriver<AndroidElement> driver, String direction) {
            switch (direction.toLowerCase()) {
                case "up":
                    SwipeUp(driver);
                    break;
                case "down":
                    SwipeDown(driver);
                    break;
                case "left":
                    SwipeLeft(driver);
                    break;
                case "right":
                    SwipeRight(driver);
                    break;
                default:
                    System.out.println("方向参数不对,只能是up、down、left、right");
                    break;
            }
        }


        /**
         * 上滑
         *
         * @param driver
         */

        public static void SwipeUp(AndroidDriver<AndroidElement> driver) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Dimension size = driver.manage().window().getSize();
            int height = size.height;
            int width = size.width;
            new TouchAction(driver).longPress(PointOption.point(width / 2, 100))
                    .moveTo(PointOption.point(width / 2, height - 100)).release()
                    .perform();

        }


        /**
         * 下滑
         *
         * @param driver
         */

        public static void SwipeDown(AndroidDriver<AndroidElement> driver) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Dimension size = driver.manage().window().getSize();
            int height = size.height;
            int width = size.width;
            new TouchAction(driver)
                    .longPress(PointOption.point(width / 2, height - 100))
                    .moveTo(PointOption.point(width / 2, 100)).release().perform();
        }


        /**
         * 左滑
         *
         * @param driver
         */

        public static void SwipeLeft(AndroidDriver<AndroidElement> driver) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Dimension size = driver.manage().window().getSize();
            int height = size.height;
            int width = size.width;
            new TouchAction(driver)
                    .longPress(PointOption.point(width - 100, height / 2))
                    .moveTo(PointOption.point(100, height / 2)).release().perform();
        }


        /**
         * 右滑
         *
         * @param driver
         */

        public static void SwipeRight(AndroidDriver<AndroidElement> driver) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Dimension size = driver.manage().window().getSize();
            int height = size.height;
            int width = size.width;
            new TouchAction(driver).longPress(PointOption.point(100, height / 2))
                    .moveTo(PointOption.point(width - 100, height / 2)).release()
                    .perform();
        }
  • 获取属性:getAttribute()
  • 获取文本:getText()
  • 获取资源:getPageSource()
  • 元素定位,两种方式。
    • 第一种使用 sdk 中的【uiautomatorviewer.bat】进行元素定位
      打开:

双击 uiautomatorviewer.bat 即可弹出:

在操作上面之前需要链接手机或者链接模拟器并操作命令显示:adb devices
如果是模拟器需要先链接:adb connect 127.0.0.1:62001 这样再次链接.

模拟器链接显示:

点击 sdk 中的【uiautomatorviewer.bat】

链接成功显示:

鼠标点击某个控件就会提示该控件可操作的相应内容:

说明:

其实在做移动端自动化测试,定位方式很少基本就是 id/name/xpath/ 坐标等定位方式。

五、常见定位方式

1、ID 定位

 driver.findElement(By.id("xxxxxx")).click();

2、name定位

 driver.findElement(By.name("xxxxxx")).click();

3、xpath 定位

xpath定位是最常用的一种方式,可以去学习下 xpath 语法:

但是网上也有大牛做一个插件,做 ui 自动化可直接使用:- https://github.com/lazytestteam/lazyuiautomatorviewer

大家下载后替换 sdk 中的 uiautomatorviewer.jar 就可使用。

点击 uiautomatorviewer.bat 再次弹出如下:

driver.findElement(By.xpath("xxxxxx")).click();

4、定位 h5 页面

启动:

点击:

再弹出对话中输入:

在下面选项框中输入:
需要获取 appPackage 与 appActivity

使用命令:

aapt d badging pinduoduov4.76.0_downcc.com.apk |findstr "package launchable-activity"

获取结果:

{  "platformName": "Android",  "deviceName": "127.0.0.1:62001",  "appPackage": "com.xunmeng.pinduoduo",  "appActivity": "com.xunmeng.pinduoduo.ui.activity.MainFrameActivity"}

点击启动:

显示正在启动:

启动完毕显示:

启动完毕,剩下的就是常用与其他操作一样:

六、简单 demo 示例

    import io.appium.java_client.AppiumDriver;
    import io.appium.java_client.TouchAction;
    import io.appium.java_client.android.AndroidDriver;
    import io.appium.java_client.android.AndroidElement;
    import io.appium.java_client.android.AndroidKeyCode;
    import io.appium.java_client.functions.ExpectedCondition;
    import io.appium.java_client.remote.AndroidMobileCapabilityType;
    import io.appium.java_client.remote.MobileCapabilityType;
    import io.appium.java_client.touch.LongPressOptions;
    import io.appium.java_client.touch.WaitOptions;
    import io.appium.java_client.touch.offset.PointOption;
    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.*;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.time.Duration;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;


    /**
     * @author 7DGroup
     * @Title: Bases
     * @Description: 安装初始化类
     * @date 2019/11/20 / 22:34
     */

    public class DriverBase {


        public static AndroidDriver<AndroidElement> driver;

        /**
         * @param port :服务器启动的端口号,系统自动获取
         * @param udid :手机设备号:系统自动化获取
         * @param apk  :自动化运行的APK包,系统会根据该地址获取包名与actiber
         * @param flag :true 卸掉有重新安装与运行后自动化卸掉包。false 直接安装运行
         * @return

         */

        public static AndroidDriver<AndroidElement> initDriver(String port, String udid, String apk, boolean flag) {
            ArrayList<String> packAct = OperationalCmd.getPackAct(apk);
    //        File app = new File(".\\\\apk\\\\20171026.apk");
            DesiredCapabilities caps = new DesiredCapabilities();
            //自动安装
            if (flag) {
                caps.setCapability(MobileCapabilityType.APP, apk);
                //结束后会卸载程序
                caps.setCapability(MobileCapabilityType.FULL_RESET, AndroidCapabilityType.FULL_RESET);
            }

            caps.setCapability(AndroidMobileCapabilityType.APPLICATION_NAME, udid);
            //PLATFORM_NAME: 平台名称
            caps.setCapability(AndroidMobileCapabilityType.PLATFORM_NAME, AndroidCapabilityType.PLATFORM_NAME);
           
           //UDID:设置操作手机的唯一标识,android手机可以通过adb devices查看
            caps.setCapability(MobileCapabilityType.DEVICE_NAME, udid);
           
           //NEW_COMMAND_TIMEOUT: appium server和脚本之间的 session超时时间
            caps.setCapability(AndroidCapabilityType.NEW_COMMAND_TIMEOUT, AndroidCapabilityType.NEW_COMMAND_TIMEOUT);
            
            //APP_PACKAG:Android应用的包名
            caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, packAct.get(0));

            //APP_ACTIVITY :启动app的起始activity
            caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, packAct.get(1));

            //UNICODE_KEYBOARD:1、中文输入不支持,2、不用它键盘会弹出来,说不定会影响下一步操作.需要注意设置后,需要将手机的输入法进行修改
            caps.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, AndroidCapabilityType.UNICODE_KEY_BOARD);

            //Reset_KEYBOARD:是否重置输入法
            caps.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD, AndroidCapabilityType.RESET_KEY_BOARD);

            //NO_SIGN:跳过检查和对应用进行 debug 签名的
            caps.setCapability(AndroidMobileCapabilityType.NO_SIGN, AndroidCapabilityType.NO_SIGN);

            try {
                //appium测试服务的地址
                String serverUrl = "http://127.0.0.1";
                driver = new AndroidDriver<>(new URL(serverUrl +以上是关于移动端自动化 AutoJS 快速入门指南的主要内容,如果未能解决你的问题,请参考以下文章

移动端自动化测试工具 Appium 快速入门

autojs保存后自动增加了代码

译文:18个实用的JavaScript代码片段,助你快速处理日常编程任务

auto.js如何解析html

Sortable.js 拖拽导致移动端不能点击问题

移动端自动化测试Appium从入门到项目实战Python版 学习 教程