Android 7~10无障碍服务模拟滑动手势(AccessibilityService#dispatchGesture)流畅地卡顿

现在的Android真像个弱智,作为用户恼火多年,着手开发后惊觉没有弄错,这系统是真的该死。

习惯了PC裸奔,Windows上模拟用户操作的接口随随便便就能调用,Android里仅有的办法就是无障碍服务和连接电脑。这电脑有什么稀奇的?当前手机的硬件可比我现在用的这台老爷电脑强多了。无障碍服务虽然自古就有,真要拿它来做点什么事,立马就不行了。Android 4.1总算是加了点跟模拟操作有关的函数;直到Android 7,可总算是把模拟点击和滑动之类的功能加上了。

谁能解释一下AccessibilityService.java里直到Android 11才改掉的这行代码?

List<GestureDescription.GestureStep> steps = MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);

100是对输入手势路径的采样间隔,单位是毫秒。也就是说Android 11以前无障碍服务模拟滑动的卡顿完全是人为的。当初设定卡顿间隔0.1秒有什么原因吗?系统数次升级后取消卡顿有什么原因吗?都没有吗?该不会是真想造成“系统在优化了”的假象吧?这甚至能算是借口吗?

好就好在Java同样是人间之屑!要用反射的话,就要import java.lang.reflect.*;。除了世界上最好的编程语言,把反射一词掺入名称的还有谁?这玩意简直就跟人生作弊器一样,用它连私有成员都能写入。

这时候有人肯定要问了:Android 9以降,内部接口都关小黑屋去了,怎么反射得了?人民的力量是无穷的,tiann/FreeReflection几十行代码就教Android拱手而降。此中原理作者已讲述得清楚,我不再废话。

所以我的最终答案是用反射重写一遍dispatchGesture,把100改成16。如果你打得过Java编译器,可以把原来的dispatchGesture实现直接抄来改,不用反射,那是最好。我就偷个懒,不跟编译器说理去;我这儿没用到回调,便也不抄全了。


Android 11才姗姗来迟的截图接口AccessibilityService#takeScreenshot同样有大问题:每秒仅限调用一次,Android 12放宽到每秒三次。我寻思这不就跟dispatchGesture一样,开发者心情好(也可能是不好)就随便改改参数,水水提交?但这回的判断写在了connection的另一侧,和权限判断在一起,可能没有办法了。如果你想到了什么破解的好办法,请务必告诉我。

if (mRequestTakeScreenshotTimestampMs != 0
        && (currentTimestamp - mRequestTakeScreenshotTimestampMs)
        <= AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS) {
    sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT,
            callback);
    return;
}

我相信像这样莫名其妙的限制还有很多,而这绝不是在保护用户。


照着其他语言的思路,我本来想搞个钩子拦截getGestureStepsFromGestureDescription,查了一圈的结论是没法直接钩住方法。后来发现自己重新实现其实更快。为什么说其他语言?Salenzo/MyApplication已经成了多语言项目……拉倒吧,我可学不来Java;可它实在到处都是,道听途说,耳濡目染,八方来客,群魔乱舞,不会作诗也会吟。至于Kotlin,叫IDE自动修复糙码便是;上回这么干还是用Clang的警告与错误学习C++的时候。我至今也不知道Python是如何好用的——一门用内置函数把变量名“str”“list”和“map”都给占了、内置urllib库就如同采样间隔硬编码为0.1秒的dispatchGesture一般慢的语言究竟有哪里好?要生产胶水,大可不受这气。

Android 7~10无障碍服务模拟滑动手势(AccessibilityService#dispatchGesture)流畅地卡顿》上有1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注