感谢 @codeskyblue 的开源精神
https://github.com/openatx/uiautomator2
https://testerhome.com/topics/11357

JAVA 版 atx-cli 地址: https://github.com/tigerge000/atxuiautomatorclient

背景

由于我们这边正在进行 app 自动化工具选型,目前暂定选用 macaca,但 macaca 存在没有无线测试连接方案,后来在论坛上看到 @codeskyblue 开源的 atx-agent 方案,非常感兴趣,然后花了 2 天功夫看了相关的几块源码,由于只有 python 版本的 atx-cli,因此考虑 写个 java 版 atx-cli
从开始写到现在还不到一个星期,现在开源出来主要考虑,有兴趣的小伙伴可以一起写下

目前已实现

初始化:

@Before
    public void setUp() throws Exception{
        DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
        desiredCapabilities.setPackageName("com.netease.cloudmusic");
        desiredCapabilities.setRemoteHost("192.168.2.81");
        driver.initDriver(desiredCapabilities);
    }

目前元素查找实现以下方法:

elementByName

driver.elementByName("私人FM").click();

elementByDesc

driver.elementByDesc("转到上一层级").click();

elementById

driver.elementById("com.netease.cloudmusic:id/search_src_text").sendKeys(keys);

elementByMult

一个元素多个属性定位

Map<String,Object> songParams = new HashMap<String,Object>();
        songParams.put(MaskNum.TEXT_STARTS_WITH.getDes(),"搜索");
        songParams.put(MaskNum.CLASS_NAME.getDes(),"android.widget.TextView");
driver.elementByMult((songParams)).click();

elementByXpath

在原方法不支持 xpath 基础上增加 xpath 的支持

String xpath = "//*[@resource-id=\"com.netease.cloudmusic:id/gt\"]/*[@class=\"android.widget.LinearLayout\"][4]/*[@class=\"android.widget.LinearLayout\"][1]/*[@class=\"android.widget.RelativeLayout\"][1]";
driver.elementByXpath(xpath).click();

获取当前 activity

driver.getCurrentActivity()

获取 APP activity 的 xml 结构

driver.dumpHierarchy();

完整例子

package atx.client;

import atx.client.enums.MaskNum;
import atx.client.model.DesiredCapabilities;
import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by 飞狐 on 2018/4/22.
 */
public class AtxClientTest {

    AtxClient driver = new AtxClient();

    @Before
    public void setUp() throws Exception{
        DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
        desiredCapabilities.setPackageName("com.netease.cloudmusic");
        desiredCapabilities.setRemoteHost("192.168.2.81");

        driver.initDriver(desiredCapabilities);
    }

    @Test
    public void testNetE() throws Exception{

        driver.elementByName("私人FM").click();
        driver.elementByDesc("转到上一层级").click();
        driver.elementByName("每日推荐").click();
        driver.elementByDesc("转到上一层级").click();
        driver.elementByName("歌单").click();
        driver.elementByDesc("转到上一层级").click();
        driver.elementByName("排行榜").click();
        driver.elementByDesc("转到上一层级").click();
    }

    /**
     * 搜索歌曲
     */
    @Test
    public void testSearchSong() throws Exception{
//        driver.elementByDesc("搜索").click();

        Map<String,Object> searchParams = new HashMap<String,Object>();
        searchParams.put(MaskNum.DESCRIPTION.getDes(),"搜索");
        searchParams.put(MaskNum.CLASS_NAME.getDes(),"android.widget.TextView");
        driver.elementByMult(searchParams).click();


        String keys = "大王叫我来巡山";

        driver.elementById("com.netease.cloudmusic:id/search_src_text").sendKeys(keys);

        Map<String,Object> songParams = new HashMap<String,Object>();
        songParams.put(MaskNum.TEXT_STARTS_WITH.getDes(),"搜索");
        songParams.put(MaskNum.CLASS_NAME.getDes(),"android.widget.TextView");
        driver.elementByMult((songParams)).click();

        //选择一个音乐开始播放咯
        String xpath = "//*[@resource-id=\"com.netease.cloudmusic:id/gt\"]/*[@class=\"android.widget.LinearLayout\"][4]/*[@class=\"android.widget.LinearLayout\"][1]/*[@class=\"android.widget.RelativeLayout\"][1]";
        driver.elementByXpath(xpath).click();

        driver.sleep(5000);

        //由于xml不断变化,导致 播放暂停无法找到,因此直接使用xpath进行解决

        System.out.println("播放暂停");
        String xpath1 = "//*[@content-desc=\"播放暂停\"]";

        driver.elementByXpath(xpath1).click();


        System.out.println("转到上一层级");
        driver.elementByDesc("转到上一层级").click();

        driver.elementByDesc("收起").click();

    }

    /**
     * 查找多级元素
     */
    @Test
    public void testElements() throws Exception{
        driver.dumpHierarchy();
        driver.elementByXpath("//*[@resource-id=\"com.netease.cloudmusic:id/gt\"]/*[@class=\"android.widget.LinearLayout\"][1]/*[@class=\"android.widget.LinearLayout\"][3]/*[@class=\"android.widget.ImageView\"][1]").click();
    }

    /**
     * 测试杂七杂八
     */
    @Test
    public void testGetOther() throws Exception{
        System.out.println(driver.getCurrentActivity());
    }

}

Key Events(已完成)

driver.press(KeyEventEnum.VOLUME_DWON.getValue());

截图

String fileName = "/Users/huqingen/Desktop/Finger/Git/test/atxuiautomatorclient/picture/1.jpg";
driver.takeScreenshot(fileName);

支持 adb 命令方法 (也支持元素查找及点击)

@xuxu (xuxu) 的开源代码整合到框架上
https://github.com/gb112211/Adb-For-Test

       private DesiredCapabilities desiredCapabilities = new DesiredCapabilities();

    @Before
    public void setUp() throws Exception{

        desiredCapabilities.setPackageName("com.tuotuo.solo");
        desiredCapabilities.setRemoteHost("192.168.2.81");

        driver.initDriver(desiredCapabilities);
    }

     @Test
    public void testAdbEl(){
     AdbDevice adbDevice = AdbDevice.getInstance(desiredCapabilities);
        Position position = Position.getInstance(desiredCapabilities);

        //获取设备信息

        System.out.println("设备序列号: " + adbDevice.getDeviceId());
        System.out.println("设备名称: " + adbDevice.getDeviceName());
        int[] resolution = adbDevice.getScreenResolution();
        System.out.println("设备屏幕分辨率: " + resolution[0] + "x" + resolution[1]);
        System.out.println("设备Android版本: " + adbDevice.getAndroidVersion());
        System.out.println("设备SDK版本: " + adbDevice.getSdkVersion());
        System.out.println("设备电池状态: " + adbDevice.getBatteryStatus());
        System.out.println("设备电池温度: " + adbDevice.getBatteryTemp());
        System.out.println("设备电池电量: " + adbDevice.getBatteryLevel());


        if(position.waitForElement(ElementAttribs.TEXT,"账号",WAIT_TIMEOUT)) {
            ElementAdb e_search = position.findElementById("com.tuotuo.solo:id/rl_exchange_code");
            adbDevice.click(e_search);
        }

        if(position.waitForElement(ElementAttribs.TEXT,"输入兑换码,兑换后即刻生效",WAIT_TIMEOUT)) {
            ElementAdb e_search = position.findElementByText("输入兑换码,兑换后即刻生效");
            adbDevice.click(e_search);
            adbDevice.sendText("hahahahah");
            driver.press(KeyEventEnum.ENTER.getValue());
            ElementAdb e_txt = position.findElementByText("兑换码");
            adbDevice.click(e_txt);
            ElementAdb e_enter = position.findElementByText("确定兑换");
            adbDevice.click(e_enter);
        }
}


↙↙↙阅读原文可查看相关链接,并与作者交流