公众号:arigeweixin

V1

2022/07/12阅读:23主题:默认主题

记一次抖音辅助查找经验

背景

全民短视频,mcn机构的遍地开花,mcn的的生存、发展就要想各种各样的办法。在一个数据导向的社会,大家都希望通过数据获取更多、更准确的数据,于是有朋友希望统计下进入抖音直播间的人数和人物的基础信息。 想到之前写的一个自动翻页的小工具,想来这个事情还不是手拿把掐的小事嘛?于是就一口答应了。 于是就遇到了一系列的问题。

正常的流程

1、通过工具定位具体的view

2、根据业务,对view进行操作

遇到的问题

怎么查找希望的view? 赶时间的同学可以直接看最后的捷径整理

常用工具

2.1.1、ddms中的 dump view hierarchy for ui automator 新版本Android studio中已经不提供 可以尝试在Android sdk路径下,查看tools/monitor 是否存在,存在即还有可能能用。

2.1.2、上面提供的工具如果可用,还有一个简化版本的,可以直接在tools/bin下查找 uiautomatorviewer 功能和上面的一样

正常是这样的效果

还有就是利用adb命令,adb命令的方法看起来比较头疼,就不举例了,具体的可以自己搜索下。

出师不利

上面的工具已经用的比较多了,就以为解决这个问题就是分分钟的事情。还是自己年轻了。 尝试了2.1.1方法,然后一直失败

最开始以为是工具不对,内存导致的 就换了2.1.2的工具。还是不行。但是发现了一个重要的现象 如果页面上面的变化内容比较少的话,就能抓取到,多了就不行了 ,结合保存怀疑是因为在生成view hierarchy的时候,直播页面已经发生了变化,导致生成失败。

要不尝试反编译下apk?

说干就干,使用jadx对apk进行反编译,8g内存直接被爆了,重新配置为16g,正常跑起来了。 看了下代码,觉得头疼,要不还是想下其他方案吧。不得不说,直播页真的是有点头疼 1、activity竟然还要使用代理来处理 2、使用了万恶的event bus 3、对资源进行了混淆和代理 整体来说,如果去看这个代码的话,就比较头疼,要花比较多的精力。

要不先xp hook下?

这个好像成本也比较大。作为兜底方案。

柳暗花明又一村

本来以为没有其他的更好方案了,后来一想,不对,我们既然已经使用了辅助功能,为啥不考虑用api来做呢? 说干就干。 1、我们的service直接继承自 AccessibilityService 我们之前的业务也都在这个里面处理。

    public abstract void onAccessibilityEvent(AccessibilityEvent event);

关注到 AccessibilityEvent 下有

    public @EventType int getEventType() {
        return mEventType;
    }

查看EventType:

    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
            TYPE_VIEW_CLICKED,
            TYPE_VIEW_LONG_CLICKED,
            TYPE_VIEW_SELECTED,
            TYPE_VIEW_FOCUSED,
            TYPE_VIEW_TEXT_CHANGED,
            TYPE_WINDOW_STATE_CHANGED,
            TYPE_NOTIFICATION_STATE_CHANGED,
            TYPE_VIEW_HOVER_ENTER,
            TYPE_VIEW_HOVER_EXIT,
            TYPE_TOUCH_EXPLORATION_GESTURE_START,
            TYPE_TOUCH_EXPLORATION_GESTURE_END,
            TYPE_WINDOW_CONTENT_CHANGED,
            TYPE_VIEW_SCROLLED,
            TYPE_VIEW_TEXT_SELECTION_CHANGED,
            TYPE_ANNOUNCEMENT,
            TYPE_VIEW_ACCESSIBILITY_FOCUSED,
            TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
            TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
            TYPE_GESTURE_DETECTION_START,
            TYPE_GESTURE_DETECTION_END,
            TYPE_TOUCH_INTERACTION_START,
            TYPE_TOUCH_INTERACTION_END,
            TYPE_WINDOWS_CHANGED,
            TYPE_VIEW_CONTEXT_CLICKED,
            TYPE_ASSIST_READING_CONTEXT
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface EventType {}

看到了心心念念的 TYPE_VIEW_CLICKED 我觉得看到了光明。

2、就干,代码安排上。 开启辅助,触发对应view的点击事件。激动人心的事情发生了

真的输出了对应的view id和text!!!

3、使用

findAccessibilityNodeInfosByViewId(String viewId)

获取对应的nodeInfo,然后对其进行点击操作。

原本平淡无奇的操作,竟然再起波澜。

波澜再起

发现对前面找到的view进行点击操作的时候,无法触发效果。 但是我刚才点击的时候抓到的明明是这个view啊,text内容也是对的,怎么回事呢? 先看下这个view是不是clickable吧,万一没有这个功能呢?

List<AccessibilityAction> getActionList()

nodeInfo提供了查看当前节点所有的action的列表,也有对应的含义。其中我们比较关注的是这个

    public static final int ACTION_CLICK = 0x00000010;

遗憾的是前面找到的view并没有这个action。

完美结局

回想Android的事件传递机制,如果一个view没有拦截点击事件,但是点击事件还被响应了,那就只有一个情况--当前的view的父布局或者子布局把事件给处理了。 兵分两路 通过:

getParent()
getChild(i)

去查看对应的父view和子view,并检查他们对应的action是否有click。 功夫不负有心人。最终确认了,view的父布局中有click的action。对父view进行操作,也获得了期望的效果。至此这个问题被解决。

捷径整理

1、利用AccessibilityService中onAccessibilityEvent的event 的clicktype,缩小view的查找范围。

2、校验view是否是想要确认的view

3、如果是需要view,但是无法响应事件,可以查找他的父布局或者子布局上能够响应click的view

4、确定最终要确定的view

5、不要被之前的经验所束缚,要多使用系统给的api,要多思考系统原理。

关注公众号: arigeweixin ,取得更多联系

分类:

移动端开发

标签:

Android

作者介绍

公众号:arigeweixin
V1