上一篇介绍了的这个系列的背景【玩转Android自动化】开篇序言 接下来就开端一步一步完成吧

工欲善其事必先利其器

  • 接触Android无障碍(AccessibilityService)功用开发首要遇到的问题就是怎样获取页面上的元素信息,只要拿到元素仅有标识信息(比如元素id或许text)才能通过调用系统的findAccessibilityNodeInfosByViewId()findAccessibilityNodeInfosByText()去获取这个元素,然后对这个元素进行相关操作,比如常见的点击某个元素、获取某个元素的内容、滑动一下屏幕等相似的操作,通过这些操作就能组合成一条完好的业务流程。

怎样获取元素

  • 惯例获取页面元素的办法是使用Android Studio的LayoutInspector进行检查页面元素信息,可是这种办法有一个致命的问题就是APP要敞开debug形式才能够获取到页面元素,所以要想分析其他市场上的APP是行不通的(不考虑模拟器或许root机),当然在历史的长河中还存在过Android Device MonitorUI Automator Viewer,这两个东西也能够获取到节点元素信息,不过基本上算是被淘汰了,这儿就不翻开讲了,感兴趣的能够网上搜搜有许多现成的材料

  • 本文要介绍的是直接通过代码获取当前屏幕窗口的根节点,然后一层一层的遍历,最终打印出自己需求的相对重要的节点信息即可,有了这么一套东西之后就能够对你想处理的页面能够很便利的获取页面元素,让自己只专注于详细的业务流程开发就能够了,能够节约大部分查找页面元素的时间。

详细完成

完成思路

  • AccessibilityService类中有个getRootInActiveWindow()办法,他能够获取到当前活动窗口的根节点,回来的是AccessibilityNodeInfo目标,然后能够拿到它的childCount,通过循环遍历就能够查找到一切的子节点了,节点包含的信息许多,咱们一般需求是classNametextviewIdResourceNamedescriptionisClickableisScrollableisEditable这些基础数据,为了便利打印出咱们需求的数据,首要定义一个包装类NodeWrapper,重写它的toString()办法,这样就能够按照既定的格局输出一些咱们需求的信息了
data class NodeWrapper(
    var className: String,
    var text: String? = null,
    var id: String? = null,
    var description: String? = null,
    var isClickable: Boolean = false,
    var isScrollable: Boolean = false,
    var isEditable: Boolean = false,
    var nodeInfo: AccessibilityNodeInfo? = null
) {
    override fun toString() = "className = $className → text = $text → id = $id → description = $description → isClickable = $isClickable → isScrollable = $isScrollable → isEditable = $isEditable"
}

代码设计

  • 咱们把这个打印节点信息的办法定义为printNodeInfo(),由于rootInActiveWindow()回来是AccessibilityNodeInfo目标,所以为了便利调用咱们定义一个AccessibilityNodeInfo类的扩展办法,大致内容如下:
fun AccessibilityNodeInfo?.printNodeInfo() {
    val node = this ?: return
    //挑选咱们需求的信息包装起来,便于打印
    val nodeWrapper = NodeWrapper(
        className = node.className.default(),
        text = node.text.default(),
        id = node.viewIdResourceName.default(),
        description = node.contentDescription.default(),
        isClickable = node.isClickable,
        isScrollable = node.isScrollable,
        isEditable = node.isEditable,
        nodeInfo = node
    )
    //打印咱们需求的信息
    Log.d("printNodeInfo", nodeWrapper.toString())
    val size = node.childCount
    if (size > 0) {
        //通过递归调用去打印子节点的信息
        for (index in 0 until size) {
            node.getChild(index).printNodeInfo()
        }
    }
}

怎样使用

  • 首要需求定义一个承继AccessibilityService类的子类TestAccessibilityService类,重写onCreate()办法,在里边进行初始化赋值给咱们定义的全局变量testAccessibilityService = this
    companion object {
        var testAccessibilityService: AccessibilityService? = null
    }
    override fun onCreate() {
        super.onCreate()
        testAccessibilityService = this
    }
    override fun onDestroy() {
        testAccessibilityService = null
        super.onDestroy()
    }
  • 然后在需求的当地就能够调用testAccessibilityService?.rootInActiveWindow?.printNodeInfo()进行打印节点信息了。先来看下作用吧
【玩转Android自动化】布局节点速查器
className = android.widget.FrameLayout → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.LinearLayout → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.FrameLayout → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.LinearLayout → text =  → id = com.android.wechat.tools:id/action_bar_root → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.FrameLayout → text =  → id = android:id/content → description =  → clickable = false → scrollable = false → editable = false
className = android.view.ViewGroup → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.LinearLayout → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.view.ViewGroup → text =  → id = com.android.wechat.tools:id/toolbar → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.TextView → text = 微信自动化东西 → id =  → description =  → clickable = false → scrollable = false → editable = false
className = androidx.appcompat.widget.LinearLayoutCompat → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.view.ViewGroup → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.FrameLayout → text =  → id = com.android.wechat.tools:id/nav_host_fragment_content_main → description =  → clickable = false → scrollable = false → editable = false
className = android.view.ViewGroup → text =  → id =  → description =  → clickable = false → scrollable = false → editable = false
className = android.widget.Button → text = 无障碍服务已敞开 → id = com.android.wechat.tools:id/btn_open_service → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 页面元素检测东西 → id = com.android.wechat.tools:id/btn_print_node → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 获取微信老友列表 → id = com.android.wechat.tools:id/btn_get_friend_list → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 一键检测《通过假转账办法》 → id = com.android.wechat.tools:id/btn_check → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 一键检测《通过拉群办法》 → id = com.android.wechat.tools:id/btn_check_by_group → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 微信自动抢红包 → id = com.android.wechat.tools:id/btn_wx_auto_hb → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.Button → text = 微信自动回复音讯 → id = com.android.wechat.tools:id/btn_wx_auto_reply → description =  → clickable = true → scrollable = false → editable = false
className = android.widget.TextView → text =  → id = com.android.wechat.tools:id/tv_task_des → description =  → clickable = false → scrollable = false → editable = false
className = androidx.recyclerview.widget.RecyclerView → text =  → id = com.android.wechat.tools:id/recycler_view → description =  → clickable = false → scrollable = false → editable = false
className = android.view.View → text =  → id = android:id/statusBarBackground → description =  → clickable = false → scrollable = false → editable = false
  • 能够看到当前窗口的元素都现已被详细的打印出来了,不过这样打印出来看起来怪怪的,总感觉是哪里有问题,看了半响发现,输出的节点都是同一级的,看不出来父子元素的关系,这样就会呈现咱们想要检查某个元素的父节点的时分就特别费力,假如页面简单还好,稍微杂乱点的页面能把人看懵逼。那么该怎样去展现父子节点的关系呐,突然想到咱们gradle中有个dependenciestask,这个task能够打印出出咱们所依靠库中的详细依靠关系,也就是咱们需求的父子关系,咱们能够先看一下它输出的是什么样的。
+--- androidx.core:core-ktx:1.7.0
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.31 -> 1.7.10 (*)
|    +--- androidx.annotation:annotation:1.1.0 -> 1.3.0
|    \--- androidx.core:core:1.7.0
|         +--- androidx.annotation:annotation:1.2.0 -> 1.3.0
|         +--- androidx.annotation:annotation-experimental:1.1.0
|         +--- androidx.lifecycle:lifecycle-runtime:2.3.1
|         |    +--- androidx.lifecycle:lifecycle-common:2.3.1
|         |    |    \--- androidx.annotation:annotation:1.1.0 -> 1.3.0
|         |    +--- androidx.arch.core:core-common:2.1.0
|         |    |    \--- androidx.annotation:annotation:1.1.0 -> 1.3.0
|         |    \--- androidx.annotation:annotation:1.1.0 -> 1.3.0
|         \--- androidx.versionedparcelable:versionedparcelable:1.1.1
|              +--- androidx.annotation:annotation:1.1.0 -> 1.3.0
|              \--- androidx.collection:collection:1.0.0 -> 1.1.0
|                   \--- androidx.annotation:annotation:1.1.0 -> 1.3.0

能够明晰的看出层级关系,这不这个是咱们需求的吗,先来分析一下他的结构欧,根节点+--- 开端标记,每个子节点前加个|区分,然后加几个空格让他呈现父子关系的样子,假如子节点是最终一个再加个\---表明当前是层级的最终一个节点,以此类推就呈现上边展现的输出格局了,接下来看看详细代码吧

fun AccessibilityNodeInfo?.printNodeInfo(prefix: String = "", isLast: Boolean = false) {
    val node = this ?: return
    val nodeWrapper = NodeWrapper(
        text = node.text.default(),
        id = node.viewIdResourceName.default(),
        className = node.className.default(),
        description = node.contentDescription.default(),
        isClickable = node.isClickable,
        isScrollable = node.isScrollable,
        isEditable = node.isEditable,
        nodeInfo = node
    )
    val marker = if (isLast) """\--- """ else "+--- "
    val currentPrefix = "$prefix$marker"
    Log.d("printNodeInfo", currentPrefix + nodeWrapper.toString())
    val size = node.childCount
    if (size > 0) {
        val childPrefix = prefix + if (isLast) "  " else "|  "
        val lastChildIndex = size - 1
        for (index in 0 until size) {
            val isLastChild = index == lastChildIndex
            node.getChild(index).printNodeInfo(childPrefix, isLastChild)
        }
    }
}

代码不杂乱,只是在本来代码的基础上多了几个前缀字符的标记而已,现在再打印一下同一个页面信息看看作用吧

+--- className = android.widget.FrameLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  +--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |  \--- className = android.widget.FrameLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |    \--- className = android.widget.LinearLayout → text =  → id = com.android.wechat.tools:id/action_bar_root → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |      \--- className = android.widget.FrameLayout → text =  → id = android:id/content → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |        \--- className = android.view.ViewGroup → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |          +--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |          |  \--- className = android.view.ViewGroup → text =  → id = com.android.wechat.tools:id/toolbar → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |          |    +--- className = android.widget.TextView → text = 微信自动化东西 → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |          |    \--- className = androidx.appcompat.widget.LinearLayoutCompat → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |          \--- className = android.view.ViewGroup → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |            \--- className = android.widget.FrameLayout → text =  → id = com.android.wechat.tools:id/nav_host_fragment_content_main → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |              \--- className = android.view.ViewGroup → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 无障碍服务已敞开 → id = com.android.wechat.tools:id/btn_open_service → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 页面元素检测东西 → id = com.android.wechat.tools:id/btn_print_node → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 获取微信老友列表 → id = com.android.wechat.tools:id/btn_get_friend_list → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 一键检测《通过假转账办法》 → id = com.android.wechat.tools:id/btn_check → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 一键检测《通过拉群办法》 → id = com.android.wechat.tools:id/btn_check_by_group → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 微信自动抢红包 → id = com.android.wechat.tools:id/btn_wx_auto_hb → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.Button → text = 微信自动回复音讯 → id = com.android.wechat.tools:id/btn_wx_auto_reply → description =  → isClickable = true → isScrollable = false → isEditable = false
|  |                +--- className = android.widget.TextView → text =  → id = com.android.wechat.tools:id/tv_task_des → description =  → isClickable = false → isScrollable = false → isEditable = false
|  |                \--- className = androidx.recyclerview.widget.RecyclerView → text =  → id = com.android.wechat.tools:id/recycler_view → description =  → isClickable = false → isScrollable = false → isEditable = false
|  \--- className = android.view.View → text =  → id = android:id/statusBarBackground → description =  → isClickable = false → isScrollable = false → isEditable = false

哈哈,是不是瞬间好看多了,各个父子关系能够明晰的看出来,同级元素页能够一眼看出来了

  • 由于getRootInActiveWindow()是在AccessibilityService类中才有的办法,每次调用需求写一些重复性的代码,一切咱们再定义一个AccessibilityService类的扩展办法,今后直接调用xxx.printNodeInfo()就能够了
fun AccessibilityService?.printNodeInfo() {
    this ?: return
    rootInActiveWindow.printNodeInfo()
}

拓展

  • 尽管打印的代码部分完成了,这个时分又引出一个问题,比如咱们想在微信里边看某个页面的节点信息怎样办呐,总不能每次都编译一遍代码去执行打印节点的办法吧,咱们期望的是在任何页面都能够随时随地的打印,怎样在微信页面触发咱们的printNodeInfo()办法呐,自然而然的想到用悬浮窗去完成了,悬浮窗能够浮在任何页面之上,咱们只需点一下悬浮窗,然它获取AccessibilityService目标并调一下printNodeInfo()办法就能够了,关于Android悬浮窗这儿就不做过多讲解了,由于不是本文的要点,在网上找了优异的开源库直接使用就能够了。咱们看一下微信的页面信息吧
+--- className = android.widget.FrameLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|  \--- className = android.widget.FrameLayout → text =  → id = com.tencent.mm:id/fkh → description =  → isClickable = false → isScrollable = false → isEditable = false
|    \--- className = android.widget.RelativeLayout → text =  → id = com.tencent.mm:id/gv5 → description =  → isClickable = false → isScrollable = false → isEditable = false
|      \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/gv4 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        +--- className = android.widget.RelativeLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  +--- className = android.widget.ListView → text =  → id = android:id/list → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/l49 → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  |  |  +--- className = android.widget.ImageView → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |  +--- className = android.widget.TextView → text = 微信 → id = com.tencent.mm:id/b7 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |  \--- className = android.widget.TextView → text = Version 8.0.40 → id = com.tencent.mm:id/b6 → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  |  +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/iwg → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  |  |  +--- className = android.view.View → text =  → id = com.tencent.mm:id/krm → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/br8 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |    \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/gv6 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |      \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/kp3 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        +--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        |    \--- className = android.widget.TextView → text = 功用介绍 → id = android:id/title → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/its → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |      \--- className = android.widget.ImageView → text =  → id = com.tencent.mm:id/isy → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/iwg → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  |  |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/br8 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |  \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/kp3 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |    \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |      \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        \--- className = android.widget.TextView → text = 投诉 → id = android:id/title → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/its → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |      \--- className = android.widget.ImageView → text =  → id = com.tencent.mm:id/isy → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/iwg → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  |  |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    +--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/br8 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |    \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/gv6 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |      \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/kp3 → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        +--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        |  \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        |    \--- className = android.widget.TextView → text = 检查新版本 → id = android:id/title → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    |        \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |    \--- className = android.widget.LinearLayout → text =  → id = com.tencent.mm:id/its → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  |      \--- className = android.widget.ImageView → text =  → id = com.tencent.mm:id/isy → description =  → isClickable = false → isScrollable = false → isEditable = false
|        |  |  \--- className = android.widget.TextView → text =  → id = android:id/title → description =  → isClickable = true → isScrollable = false → isEditable = false
|        |  \--- className = android.view.View → text =  → id = com.tencent.mm:id/e5c → description =  → isClickable = false → isScrollable = false → isEditable = false
|        \--- className = android.widget.FrameLayout → text =  → id = com.tencent.mm:id/i1f → description =  → isClickable = false → isScrollable = false → isEditable = false
|          \--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|            +--- className = android.widget.TextView → text = 《软件答应及服务协议》 → id = com.tencent.mm:id/khc → description =  → isClickable = true → isScrollable = false → isEditable = false
|            +--- className = android.widget.LinearLayout → text =  → id =  → description =  → isClickable = false → isScrollable = false → isEditable = false
|            |  +--- className = android.widget.TextView → text = 《隐私维护指引摘要》 → id = com.tencent.mm:id/khb → description =  → isClickable = true → isScrollable = false → isEditable = false
|            |  \--- className = android.widget.TextView → text = 《隐私维护指引》 → id = com.tencent.mm:id/kha → description =  → isClickable = true → isScrollable = false → isEditable = false
|            +--- className = android.widget.TextView → text = 客服电话:400 670 0700 → id = com.tencent.mm:id/exh → description =  → isClickable = false → isScrollable = false → isEditable = false
|            \--- className = android.widget.TextView → text = 腾讯公司 版权一切

——->以下是新增功用<——-

对布局速查器相关做了重构,抽离成一个独自的module了

PC端检查数据(你相信光吗)

  • 上边介绍了通过悬浮球去打印信息,后来对打印的数据也做了简化处理,可是对使用者来说仍是不太便利,弊端有两点,一是需求手机连接到Android Studio上通过检查log的办法检查节点信息,这点在后来的实际场景中感觉很鸡肋,二是即便后来我也加了在手机端直接检查的功用,但移动端终究是小屏,看起来很费力,并且无法搜索查找。根据以上两点,连夜重构了这部分代码,让咱们的数据能够在电脑端浏览器里直接操作检查。

  • 要怎样完成手机与PC端通讯呐,这儿就用到去年我写的一个Android本地服务AndroidLocalService库了,真没想到在这儿又用到它了。对这个库不了解的能够看下源码或许看下我之前写的Android抓包从未如此简单这边文章中也用到了AndroidLocalService并且对其进行简单的介绍。

  • 借助于AndroidLocalService,咱们需求写一个html页面用于PC端浏览器预览和操作,详细的html页面编写说实话我不太拿手,偷个懒就让ChatGPT帮我简单生成了一段代码,通过简单的修正就能够正常使用了,哈哈。

【玩转Android自动化】布局节点速查器

  • 写好了页面咱们就把页面信息和对本地的读写操作都写在通过AndroidLocalService完成的AutoToolsService类中,这样一个本地服务就建立好了,大致内容如下:
@Page("")
fun getIndexPage() = "auto_tools_index.html"
@Get("getPageSimpleNodeInfo")
fun getPageSimpleNodeInfo(): String {
    ContentManger.printContent =
        AutoToolsAccessibility.autoToolsAccessibility?.printNodeInfo(true)
    return ContentManger.printContent
        ?: "暂未获取到页面节点信息,请先确保APP已敞开【布局节点速查器】无障碍功用"
}
  • 有了本地服务之后就是初始化和发动服务了
ALSHelper.init(requireContext().applicationContext)
ALSHelper.startService(ServiceConfig(AutoToolsService::class.java))
  • 然后就让咱们在电脑端点击一下按钮,看看最终作用吧

【玩转Android自动化】布局节点速查器

既然PC端页面那么大,爽性就多做点功用吧,增加:【上】【下】【左】【右】四个方向滑动屏幕、【回来】键【点击】指定节点【输入】内容,假如后边有其他需求的功用后续再增加吧!

  • 再来看下移动端作用吧

【玩转Android自动化】布局节点速查器

最终

  • 这样咱们的元素检测小东西就算悉数写完了,今后想看某个页面检查节点信息就能够直接翻开咱们的APP,敞开无障碍服务后,发动悬浮窗,翻开指定APP某个页面,点一下悬浮窗就能够在控制台看到美化后的详细的节点信息了。

  • 后续怎样有需求咱们能够把打印的节点信息直接在APP中检查,可是看出节点这种事情仍是在PC端大屏上看着才舒畅,所以暂时就不展现在手机端喽

  • 刀已磨好,接下来就开端在微信中实操吧

感兴趣的能够下载demo体会一下,在阅读源码过程遇到任何问题欢迎提Issues,假如对你有帮助,希望动动你的发财小手点个赞呗

预告

下一篇让咱们期待一下【玩转Android自动化】小试牛刀,通过一个简单的比如带大家实操一下