总结一下前面流程,首先Appium运行,推送Bootstrap.jar到设备端,而Bootstrap.jar这个jar实际上就是继承了UiAutomatorTestCase的测试类,然后通过命令运行这个jar包开始执行自动化脚本

先来看看执行命令:

adb.exe -s 5b30ee87 shell uiautomator runtest AppiumBootstrap.jar -c io.appium.android.bootstrap.Bootstrap -e pkg com.main -e disableAndroidWatchers false

这条命令的参数《 Appium基础学习之 | UiAutomator使用 》中已经有大概的介绍,但是对于uiautomator的命令没有进行详细的讲解,说到AccessibilityService中正好与这些命令有直接关系,所以有了本文。

1.help

先通过uiautomator help看看命令

(1)help:帮助

(2)runtest:执行UI自动化测试

(3)dump:创建一个当前ui视图结构的xml文件

(4)events:打印accessibility事件

从帮助中可以看到uiautomator主要的4个命令,但是有个疑问又来了,uiautomator如何在android系统的手机设备中接收到这些并运行的。

2.uiautomator的shell脚本

在uiautomator源码的cmds文件夹中找到了uiautomator的shell文件,这个文件就是作为uiautomator初始化并启动执行的入口。

export run_base=/data/local/tmp
export base=/system

# if not running as root, trick dalvik into using an alternative dex cache
if [ ${USER_ID} -ne 0 ]; then
tmp_cache=${run_base}/dalvik-cache

if [ ! -d ${tmp_cache} ]; then
mkdir -p ${tmp_cache}
fi

export ANDROID_DATA=${run_base}
fi

(1)首先定义2个变量run_base、base,值都是设备的路径(再次提醒,这个uiautomator的shell文件是在android设备中运行,shell作为Linux的一部分,在Android设备中运行就没什么好说的,不理解的可以了解一下Android系统的组成)

(2)然后判断一下是否root用户运行:通过内部变量拿到用户ID,如果拿到的ID不是0,则执行语句块内容(root用户的ID为0,非root用户的ID不是0),下面的脚本就是确定一下数据存放地址。

# take first parameter as the command
cmd=${1}

if [ -z "${1}" ]; then
cmd="help"
fi

# strip the command parameter
if [ -n "${1}" ]; then
shift
fi

CLASSPATH=/system/framework/android.test.runner.jar:${base}/framework/uiautomator.jar

(3)拿到第一个参数赋值给cmd变量,然后判断一下,如果第一个参数的值长度为0,则cmd值为help,从这里可以看到如果第一个参数没有值,肯定就是执行help的结果。

(4)再判断第一个参数的值不为空,则左移一个参数,这里需要特别注意,如果第一个参数有值,这里已经通过shift左移了一个参数

# eventually args will be what get passed down to Java code
args=
# we also pass the list of jar files, so we can extract class names for tests
# if they are not explicitly specified
jars=

# special case pre-processing for 'runtest' command
if [ "${cmd}" == "runtest" ]; then
# first parse the jar paths
while [ true ]; do
if [ -z "${1}" ]; then
echo "Error: more parameters expected for runtest; please see usage for details"
cmd="help"
break
fi
jar=${1}
if [ "${1:0:1}" = "-" ]; then
# we are done with jars, starting with parameters now
break
fi
# if relative path, append the default path prefix
if [ "${1:0:1}" != "/" ]; then
jar=${run_base}/${1}
fi
# about to add the file to class path, check if it's valid
if [ ! -f ${jar} ]; then
echo "Error: ${jar} does not exist"
# force to print help message
cmd="help"
break
fi
jars=${jars}:${jar}
# done processing current arg, moving on
shift
done

(5)如果第一个参数是runtest,cmd等于runtest,进入if语句块,然后开始循环判断,再次提醒上面已经shift左移一个参数,所以现在已经把runtest移走了,第一个参数是runtest后面的AppiumBootstrap.jar了。先判断第一个参数长度如为空,则又回到help输出让你多看看help的用法,用习惯命令的都知道,输错命令动不动就是显示help的结果。

(6)然后把第一个参数交给jar变量;进入判断,${1:0:1}的意思是取出${1}变量0到1的值,如果等于-,break回家再见;再往下不等于/,则jar=${run_base}/${1},根据上下文,jar的值得到是:/data/local/tmp/AppiumBootstrap.jar

(7)再次判断这个文件存不存在,不存在继续break回家再见;然后执行jars=${jars}:${jar},jars的值为:/data/local/tmp/AppiumBootstrap.jar(冒号前面的${jars是空})。

# look for --nohup: if found, consume it and trap SIG_HUP, otherwise just
# append the arg to args
while [ -n "${1}" ]; do
if [ "${1}" = "--nohup" ]; then
trap "" HUP
shift
else
args="${args} ${1}"
shift
fi
done
else
# if cmd is not 'runtest', just take the rest of the args
args=${@}
fi

(8)又一个循环,先判断${1}是否为空,不为空进入循环,如果参数等于--nohup,则忽略HUP信号,继续运行。可以回到上面看help帮助中的--nohub命令解释。(trap为捕捉信号,如HUP表示终端中断,INT键盘中断等等),并执行shift左移

(9)如果不等于nohup命令,取出参数值赋值给args变量。就算是命令中有--nohup,也只会进入一次if,其它都会进入else,直到取出的参数为空退出循环

(10)继续else语句块,这个else是对应上面cmd==runtest的else,也就是命令等于dump、events的时候进入,就没那么麻烦了,全部参数都复制给args

args="${cmd} ${args}"
if [ -n "${jars}" ]; then
args="${args} -e jars ${jars}"
fi

CLASSPATH=${CLASSPATH}:${jars}
export CLASSPATH
exec app_process ${base}/bin com.android.commands.uiautomator.Launcher ${args}

(11)args的值${cmd} ${args},注意中间有个空格,然后进入一个判断,判断${jars}的值是否为空,而只有runtest的时候,才不会为空。所以runtest的时候,args的值:runtest -e jars ${jars},其他时候args的值都为${cmd} ${args}

(12)${CLASSPATH}:${jars}处理后CLASSPATH的值:

/system/framework/android.test.runner.jar:/system/framework/uiautomator.jar::/data/local/tmp/AppiumBootstrap.jar

(13)export引入这些jar包,其中包含uiautomator.jar这个重量级的jar包。在uiautomator使用过程中,引入的是在本地引入,而在android设备中运行时,是从android中引入,所以在编写代码过程中一定要注意,编程环境用的版本需要小于等于运行环境的版本。

(14)通过app_process指定命令的工作路径为/system/bin,并运行com.android.commands.uiautomator.Launcher类传入的参数为${args}

总结一下前面流程,首先Appium运行,推送Bootstrap.jar到设备端,而Bootstrap.jar这个jar实际上就是继承了UiAutomatorTestCase的测试类,然后通过命令运行这个jar包开始执行自动化脚本先来看看执行命令:adb.exe -s 5b30ee87 shell uiautomator runtest AppiumBootstrap.jar -c... 博主博客网站:https://blog.zhenglin.work 干货满满 ​ 本人从事过很长一段时间的自动化测试,其中安卓的自动化主要选用的 uiautomator 框架,我这里阐述一下 uiautomator 自动化测试的原理,从整体入手、化繁为简,可以轻松理解这款框架精妙之处。就相当于有了屋子的图纸,再分步来添砖加瓦就容易的多。
今天在用appnium测试夜神模拟器的时候遇到过这样一个报错 UiAutomator exited unexpectedly with code 0, signal null [ UiAutomator ] Moving to state 'stopped' 这个错误出现在appnium界面上。 # 命令 行进入adb shell adb shell cd data/local/tmp/ #修改 Appium Bootstra为 Appium Bootstrap.jar mv Appium Bootstra Ap
android list:列出机器上所有已经安装的Android版本和AVD设备 android list avd:列出机器上所有已经安装的AVD设备; android list target:列出机器上所有已经安装的Android版本 android create ...
命令 行如下: adb shell uiautomator runtest Test.jar -e runtype repeat -c com.yuchaolee.lau.MyTest.MTest 里面有个参数e,后跟的runtype和repeat分别是值的key和value。
运行步骤: 1、在D:\software\adt-bundle-win64-20151231\adt-bundle-win64-20151231\sdk\tools目录下,输入android create uitest-project -n -t -p 比如:D:\software\adt-bundle-win64-20151231\adt-bundle-win64-20151231
```python from appium .webdriver.common.touch_action import TouchAction from appium .webdriver.common.multi_action import MultiAction # 找到ScrollView控件 scrollview = driver.find_element_by_xpath('//android.widget.ScrollView') # 获取屏幕大小 width = driver.get_window_size()['width'] height = driver.get_window_size()['height'] # 计算起始坐标和结束坐标 start_x = width // 2 start_y = height // 4 * 3 end_x = start_x end_y = height // 4 # 滑动操作 action = TouchAction(driver) action.press(x=start_x, y=start_y).move_to(x=end_x, y=end_y).release() action.perform() 通过上述代码可以实现向下滑动屏幕的操作。需要注意的是,滑动的起始坐标和结束坐标需要根据具体场景进行调整,以确保滑动操作的正确性。