用CpFastAccessibility轻松实现 → 某电商618"拆快递"自动化

又是一年618,电商平台又是常规的 价格歧视 策略:蹲点抢券、各种凑单、签到、关注店铺、加购商品、看直播等。满打满算,可能最终付款的价格比618前还贵,2333,毕竟都是 活动前先涨价

比如,前些天杰哥想给家里物色个小冰箱,标的1799,领了各种券,就差个plus的1500-50,价格可以做到1550左右,想着能省一点是一点,先加购物车,明早定个9:59的闹钟抢下券,抢到直接下单一波带走。然后我发现我想多了,当我抢到券,再打开商品页,我整个人傻了:

6啊,直接涨价到1899,而且还要预约,得过两天晚上8点才能抢,你猜我最后多少钱下单的?1650,所以整这些有的没的,最后我还多花了100块钱…

不过说回来,阿狗的活动奖励,比阿猫良心多了,属于多劳多得类型,当年阿猫搞组队PK互抢红包的恶心玩法还历历在目。关于阿狗活动的玩法,其实都是一样的,就是换个主题,活动任务的自动化方案,之前就写过了几篇文章了:

上述方案,都需要手机插着电脑跑脚本,上上周不是整活封装了一个AccessibilityService库么 → 《简单封装AccessibilityService写个库,助力Android自动化》,本节就用这个库来轻松实现自动化。


0x1、打开APP进入活动页

这一步的常规实现思路:先获得 目标APP的包名入口Activity,然后调用 startActivity() 实现跳转。

① 获得 APP的包名和入口Activity 的3种技巧

  1. 从APK文件下手 → 包名和入口Activity都会在 AndroidManifest.xml 配置文件中声明,直接找到这个文件就好~

直接解压apk文件不行的哈!!!你打开只会看到这个:

最简单快捷的方法:把APK拖到Android Studio里双击打开,搜 package= 就可以找到包名了:

接着搜 android.intent.category.LAUNCHER 就可以找到入口Activity啦:

没有安装Android Studio的话,也可以用其它反编译工具获取此文件(如:apktool


  1. 使用adb命令获取

手机接电脑,打开APP的瞬间,执行下述命令:

adb shell dumpsys activity top | grep ACTIVITY

运行结果如下:

圈着的部分:应用包名 / 应用入口Activity,而全限定类命(完整的Activity)就是前后两部分拼接而已~


  1. 使用CpFastAccessibility获得

自定义无障碍服务类时 (需继承FastAccessibilityService),重写 noAnalyzeCallBack() 直接打印 EventWrapper 参数:

运行授予无障碍后,打开电商APP:

不难看出这个 MainActivity 就是APP的入口Activity啦。是不是超简单?那这里是怎么实现的呢?简述下原理:

  • 1、无障碍配置文件设置 监听所有应用 → android:packageNames=”@null”

  • 2、重写 onAccessibilityEvent(),取出event中的关键信息丢EventWrapper实例,然后通过回调往外丢:

上面重写了 noAnalyzeCallBack(),自然能收到~


② 打开目标APP

通过上面获得的包名和入口Activity就可以精确的打开目标App了,但我想告诉你,其实 只需要一个包名,Android为我们提供了一个API:PackageManager.getLaunchIntentForPackage(packageName),语法就不展开讲了,感兴趣的自己搜关键字,直接给出封装的调用代码,除了常规判空,还加入了异常兜底:

调用方式很简单,而且会返回一个跳转成功与否的值~

Tips:因为 Android 11 的软件包可见性影响,有安装APP,但是调 getLaunchIntentForPackage()还是会返回null,需要修改下 AndroidManifest.xml,下述方法2选1:

<!-- 方法1:添加查询所有的应用的权限 -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>

<!-- 方法2:添加queries标签,声明与哪些包名的应用交互 -->
<queries>
        <package android:name="com.facebook.katana" />
        <package android:name="com.tencent.mm" />
</queries>

<queries>
    <intent>
        <action android:name="android.intent.action.SEND" />
        <data android:mimeType="image/jpeg" />
    </intent>
</queries>

③ 隐式启动Activity

在启动APP后,如何进入活动页?常规思路:找到入口节点触发点击,但在这个电商APP里完全不需要这样做,可以通过 URL Scheme(页面内跳转协议) 来隐式启动活动页,封装下工具方法:

然后如何获得这个url呢?

  • 搜索获取:有些人会分享出来,可以参考 《URL Scheme 查询指南》 提到的几个站点;
  • 应用分享URL,电脑浏览器打开,F12抓包:不过现在很多电商都不支持分享链接了,只有分享口令;
  • 写Xposed插件拦截Activity.startActivity() → 本质上还是调用 Activity.startActivityForResult() → 最终调用 Instrumentation.execStartActivity()

所以Hook下这个方法,然后把Intent的值打印出来就可以啦,限于篇幅就不展开讲啦。写个简单Hook示例:

感兴趣的可以自己试试,接着写代码调用下跳转App和页面的方法:

运行后看看效果:

好的,正常进入活动页面~


0x2、定位结点

接着就到定位结点,触发交互了,因为我们在无障碍服务配置文件里声明的 android:accessibilityFlags 包含了 flagRequestEnhancedWebAccessibility,理论上也是能拿到网页节点的。库里封装了一个打印所有页面节点的方法:

noAnalyzeCallBack() 里调用下:

然后可以看到控制台输出的节点树信息:

如果WebView里的节点没显示或者显示不全,可以尝试切换到 tbs内核 运行:

  • 给客服发送 debugtbs.qq.com,点击打开链接;
  • 选择 安装线上内核,安装完后会自动重启;
  • 重启后 选择DebugX5,不显示 请先安装内核 说明切换成功;
  • 如果不想,把APP杀掉,重新启动,重复上述操作;

简单写下做任务的样例代码:

然后是任务判定,两个思路:

  • 任务执行前,获取”去完成”节点列表,然后获取任务描述的节点列表,遍历比较y轴相差像素点少于50,建立关联关系;
  • 任务执行后,对页面中任务相关的节点进行判断,比如:滑动浏览xx可得、立即入会,立即开卡、喜欢等等。

0x3、小结

今早兴高采烈来到工位,打开电脑准备完善下脚本,才发现活动TM已经结束了,所以本节只讲解了思路,没提供完整可用的代码,甚至连运行的效果图都整不出来,尴尬…

不过,在实践开发中,发现自己写的库有很多不足的地方,比如:

  • 主动休眠1000ms有点呆,不支持轮询查找等待控件加载,就是那种waitFor();
  • 打印所有页面节点,可以整一个悬浮框来调用;
  • 多次查找结点,回调嵌套,不够优雅;
  • 等等…

当然,后续肯定是要慢慢完善,有空就会写点,有问题的小伙伴欢迎评论区留言,也可以在仓库提issues~


© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYjBJTp7' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片