基础知识

本章为您介绍安卓自动化相关的基础知识,请务必阅读本章内容,后面不再赘述。安卓自动化与常规网页自动化存在很大区别,但也有许多共性。在常规网页自动化中,可以简单地通过 F12 开发者工具查看网页布局、元素 ID 等信息,进而使用 XPath 获取元素进行点击、等待等操作。安卓环境逻辑类似,您也可以通过名为选择器的东西来选定元素并进行点击、判断等操作,因此不必担心难以入门。

移动与网页自动化的共性与区别

移动端的自动化与网页自动化之间有许多共性,当然也有不少区别。我们以 Selenium 为例:通常,使用 Selenium 进行网页控制需要三样东西:其一,浏览器;其二,WebDriver;其三,Selenium。移动端同理:手机相当于浏览器,FIRERPA 相当于 WebDriver,FIRERPA 的 Python 客户端库 lamda 相当于 Selenium,并且它们的目标一致,都是执行模拟用户操作,实现测试、数据采集或任务自动执行。它们都是通过脚本驱动、对元素进行定位、点击、截图、判断等操作。这么看,二者还是挺相像的。

但它们也有所不同。首先,移动端自动化需要一台手机和一台电脑,而网页自动化在您自己的电脑上即可进行。其次,它们使用的并非同一套方案。网页端常见工具如 Selenium、Puppeteer、Playwright;移动端则通常是 FIRERPA、AutoJS、Appium、uiautomator2 等。

对于网页端,常见的定位方式主要是基于 HTML DOM 结构的 XPath 或 CSS 选择器,元素层级相对直观。而对于移动端,常见的定位方式则是选择器;当然,安卓应用界面也使用 XML 布局,您也可以通过 XML 进行 XPath 选择。通常,网页端自动化无需过多考虑兼容性问题,大部分情况下通过固定浏览器版本和启动分辨率即可解决设备差异带来的兼容性问题。但对于安卓端,由于品牌、型号、屏幕大小、系统版本等不同,可能对自动化代码的兼容性产生影响。不过也请不必担心,虽然有影响,但程度有限。

各种自动化工具的区别

上文提到,我们举例的几种安卓端常用自动化工具之间也有很大区别。首先表明立场:FIRERPA 是所有自动化工具中最稳定、功能最全、最强大,也最适合项目化管理和应用的。

备注

我们的立场并非偏见,而是基于 6 年来不断的探索与优化而形成。您走过的路线、踩过的坑,我们基本都经历过。

常见的 AutoJS 及衍生产品属于自身控制自身类,需要在设备上安装 APK 并通过 JavaScript 编写脚本进行操作。AutoJS 通常只能进行自动化操作,优点是适合新手或业余使用,入门门槛低。但其本身的设计不适合大规模的脚本控制、管理与更新,处于去中心化、无管理的状态,无法进行精确的大规模控制。

自动化基本流程

通常您需要先预研方案:是只进行常规自动化,还是在自动化的同时获取应用运行数据?通常有两种数据获取方案:其一,通过中间人进行 HTTP/S 通信截获;其二,通过 Hook 进行数据截获。中间人方式较为简单,适合常规使用,但对部分应用可能无效。Hook 方案需要大量逆向知识,入门困难,不适合新手,适用于边缘场景。

中间人数据获取

中间人方案较简单,您只需在文档中找到 安装中间人证书设置代理 的相关内容,配合 mitmproxy 即可实现。若不清楚,还可参考官方 startmitm.py 脚本,其中已为您写好所有逻辑,可以直接复制或复用。

Hook 数据获取

Hook 方案需要具备初级及以上的逆向能力,若此前未了解,可暂不考虑。总的来说,Hook 方案是通过编写 Frida 脚本,钩住相关函数调用,获取参数或返回值并提交,然后注入应用等流程。您可在 使用 Frida 上报数据 章节了解简单 Demo 和使用方法。

自动化代码

自动化代码也是不可或缺的,因为您需要通过自动化来触发相关逻辑。编写自动化代码通常遵循以下流程。首先,打开 FIRERPA 的远程桌面,您会看到如下界面。

远程桌面

现在,打开您想要自动化操作的 APP,随后点击远程桌面右上角的“小眼睛”图标,您会看到如下界面。此时选择要操作的元素,点击即可查看元素信息。

小技巧

当然也能用代码打开,这些后面都会讲的。

选择元素

您可以看到右侧的元素信息,例如 text、resourceId 等。假设我们要点击这个元素,可编写如下代码,其含义是“点击 text 为‘同意’的元素”。

d(text="同意").click()

备注

这只是示例,选择器写法有很多,这里只介绍最简单的一种。

好了,最简单的写法您已经了解了。现在,请编写 if/else 等控制逻辑,配合 exists 等接口,您就可以实现一整套自动化操作流程了。看吧,并没有那么难。

界面布局检视

正常情况下,编写自动化代码离不开界面布局检视,这也是获取选择器条件的唯一途径。首先,在浏览器中打开设备的远程桌面。随后点击远程桌面右上角的眼睛图标进入布局检视,此时可以点击左侧屏幕上的虚线框查看对应元素信息,将其属性作为选择器的参数。再次点击眼睛图标将关闭布局检视。请注意,布局检视不会随页面变化自动刷新,它始终定格在您进入检视那一刻的屏幕布局;如需刷新,请手动按下快捷键 Ctrl + R

检视元素

提示

您也可以在布局检视界面按下 Tab 键来遍历查看所有元素。

界面选择器

界面选择器(Selector)用于操作安卓元素,您可以将其理解为 XPath 规则,虽然机制不同,但用途相似。在 FIRERPA 中,选择器类为 Selector,多数情况下您无需直接接触它。在上文中,您已见过它的用法。完整的 Selector 包含如下可选参数。

匹配类型说明
text文本完全匹配
textContains文本包含匹配
textStartsWith文本起始匹配
className类名匹配
description描述完全匹配
descriptionContains描述包含匹配
descriptionStartsWith描述起始匹配
clickable可以点击
longClickable可以长按
scrollable可滚动
resourceId资源ID匹配

大多数情况下,仅使用 resourceId、text、description、textContains 等作为参数。如果元素存在正常的 resourceId,应优先使用它作为 Selector,如 d(resourceId="com.xxx:id/mobile_signal");否则可使用 text,如 d(text="点击进入"),或者更模糊一点 d(textContains="点击")。description 与 text 同理,但 description 使用的机会较少。

提示

Selector 是由您通过上文所述界面布局检视功能获得的相关主要参数组合而成。

屏幕坐标定义

自动化操作的过程中难免会碰到需要通过精确坐标或区域坐标进行操作的情况。可能您对坐标概念还不熟悉,这里介绍安卓屏幕坐标知识。屏幕与图片一样,都有分辨率。对于安卓屏幕,无论横屏、竖屏还是自动旋转,统一将左上角作为原点 (0,0),向右为 X 轴正方向,向下为 Y 轴正方向,形成坐标系,如图所示。

屏幕坐标

由上图可知,屏幕左上角坐标为 (0,0),右上角为 (1080,0),左下角为 (0,1920),右下角为 (1080,1920)。您可以根据此信息换算屏幕上任意点的坐标。

备注

无论屏幕原生是竖屏还是横屏,亦或是自动旋转,统一以当前方向的左上角作为原点。

屏幕上的点

在 FIRERPA 中,有一些操作(如点击或截图)需要您提供区域或坐标信息。对于常见的坐标点,我们使用如下定义,它代表屏幕上坐标为 (100,100) 的点。

Point(x=100, y=100)

区域的定义

区域指屏幕上的一片矩形区域,其定义稍显繁琐,请仔细阅读。我们用 Bound 表示屏幕上的区域,需要提供四个参数:topleftbottomright。您可能有些困惑,下面请务必仔细理解:top 表示矩形顶部到屏幕顶部的像素距离,left 表示矩形左边到屏幕左边的像素距离,right 表示矩形右边到屏幕左边的距离,bottom 表示矩形底部到屏幕顶部的距离。简言之,所有距离都是以屏幕左上角原点为基准的 X/Y 轴距离。下图辅助理解,手机屏幕仍为 1080x1920,当前为竖屏状态。

屏幕区域

现在假设屏幕被四等分,我们需要获取图中所示的左上和右下两个区域的定义。根据规则,区域1:矩形顶部到屏幕顶部距离 0 像素,左边到屏幕左边距离 0 像素,底部到屏幕顶部距离 960 像素(1920÷2),右边到屏幕左边距离 540 像素(1080÷2),所以它的定义为

Bound(top=0, left=0, right=540, bottom=960)

同理,区域2:矩形顶部到屏幕顶部距离 960 像素,左边到屏幕左边距离 540 像素,右边到屏幕左边距离 1080 像素,底部到屏幕顶部距离 1920 像素,其定义为

Bound(top=960, left=540, right=1080, bottom=1920)

安卓应用的数据

每个安卓应用在设备上都有专用的数据目录。通常,应用数据存储于 /data 目录下。您可以通过调用 d.application("com.example").info() 接口获取应用的数据目录。多数情况下,也可以直接 cd/data/user/0/com.example.test 来进入用户目录。除 /data 外,部分应用还会在 /sdcard/Android 目录存储多媒体等其他文件。

查看短信数据库

有时,您想查看本机收到的短信存储位置,这非常简单,甚至通过编写扩展(extension)可以直接读取内容并通过 HTTP 接口实时获取!我们按常规安卓思路介绍,若您的情况不同,请自行发散。在安卓上,短信应用的包名通常为 com.android.mms,因此可切换到目录 /data/user/0/com.android.mms。通过以下操作,您会看到 databases 目录下有几个数据库,其中的 mmssms.db 就是我们要找的。

 λ 10:12 /data/user/0/com.android.mms ➥ ls -la
total 82
drwx------    7 u0_a78   u0_a78        3452 Jan  2  2021 .
drwxrwx--x  381 system   system       53248 May  2 16:46 ..
drwxrws--x    3 u0_a78   u0_a78_c      3452 Jan  2  2021 cache
drwxrws--x    2 u0_a78   u0_a78_c      3452 Jan  2  2021 code_cache
drwxrwx--x    2 u0_a78   u0_a78        3452 Jan  2  2021 databases
drwxrwx--x    7 u0_a78   u0_a78       24576 Feb 26 13:43 files
drwxrwx--x    2 u0_a78   u0_a78        3452 May  4 10:12 shared_prefs
 λ 10:12 /data/user/0/com.android.mms ➥ ls -l databases/
total 504
-rw-rw----    1 u0_a78   u0_a78       24576 Jan  2  2021 dynamic_bubble
-rw-------    1 u0_a78   u0_a78           0 Jan  2  2021 dynamic_bubble-journal
-rw-rw----    1 u0_a78   u0_a78      491520 Feb 27 04:18 mmssms.db
-rw-------    1 u0_a78   u0_a78           0 Jan  2  2021 mmssms.db-journal
 λ 10:12 /data/user/0/com.android.mms ➥

读取非常简单,因为安卓上常规应用数据库均为 SQLite。但安全性较高的应用通常会对数据库加密。不过,FIRERPA 功能强大,除了支持常规 SQLite,还支持实时读取微信(SqlCipher)AES-256、企业微信 AES-128、阿里系 SqlCrypto(AES-128)等加密数据库(前提是您需自行找到密钥)。下面我们简单演示读取系统短信内容,一条命令即可,您也可以编写扩展来读取。

sqlite3 databases/mmssms.db .dump

输出可能很多,但您可以快速定位所需数据所在的表,然后自行编写 SQL 查询。此方法适用于 98% 的安卓应用,剩余 2% 为加密数据库。

查看加密数据库

对于加密数据库,需由您自行找到数据库密钥或其生成方式。下面简单介绍如何读取相关应用的数据库,仅介绍如何使用 PRAGMA 预设密钥。若不清楚这是什么,请先了解 SQLite。

微信系 (sqlcipher)

PRAGMA cipher = "sqlcipher";
PRAGMA legacy = 1;
PRAGMA key = "database-key";

企业微信 (wxsqlite)

PRAGMA cipher = "aes128cbc";
PRAGMA hexkey = "database-key"

阿里系 (sqlcrypto)

PRAGMA cipher = "sqlcrypto";
PRAGMA key = "database-key"

提示

注意,安卓应用的数据库不一定只放在 databases 目录下。

查看其他数据

当然,应用数据目录中不仅有数据库,还包含应用参数、配置、缓存、文件等,如 shared_prefs(XML 文件)。我们不做过多介绍,您可以自行探索。

自动化辅助措施

在自动化业务中,并非所有应用都适合使用选择器定位。有些界面(如游戏)由于实时渲染,没有安卓层面的页面布局。对于此类应用,您只能借助 OCR 或图像匹配进行判别。请参阅 文字识别图像匹配 章节了解具体接口与用法。