实现一个蚂蚁森林自动收能量辅助工具

如图,今天我们要对这个游戏下手,抛弃每天订闹钟的烦恼:

不好意思,我放错了,蚂蚁森林是这张:

先来看看这是个什么页面: 通过查看页面的 UI 元素,可以知道蚂蚁森林是一个 Web 页面。

WKCompositingViewWKWebView 的子视图。

# 寻找收集能量关键方法

接下来的主要目标有了:在客户端调用 JavaScript 代码收取能量

如何调试任意 App 的 WebView 参见越狱环境全局开启任意 iOS App 的 WebView 调试 (opens new window)

收取能量部分内容使用 canvas 绘制,没事写写 div 的我,对 canvas 了解不多,换个思路解决该问题,收取能量必然和后台有交互,有交互就存在出错的场景,出错就有 Toast

那么试试 UNAVAILABLE 能搜出什么?

errorBubbleStateHandle 名字看起来很像收集能量出错的处理逻辑。

继续找下去:

是一个叫做 collectEnergy 的方法,似乎接近我们要的方法了,在这里打个断点,点击收集能量确认一下:

从变量 et 来看(以及 collectEnergyactions 下),collectEnergy 是 vuex 中的一个 Action。

基本可以肯定这是收集能量相关的逻辑了,只要调用这个方法,我们就能完成手动获取能量的功能。

那么再来看看调用堆栈:

找到了!this.store.dispatch("tree/collectEnergy", [d])d 应该是对应的能量球,这里还是个数组,说不定可以直接传入多个能量球,一起收集。

继续:

从这里断点可以看到 dbubblePool 获取,bubblePool 是从 this.store.state.tree.bubbles 获取。

那么直接调用 this.store.dispatch('tree/collectEnergy', this.store.state.tree.bubbles.filter(b => b.collectStatus === 'AVAILABLE')) 就可以收集当前用户的全部能量了。

# 客户端访问 this,收取能量

如何访问 this

在 Safari 上,我们可以在一些相关方法中加个断点,访问 this,更可以在加断点后执行个 window._x_tree = this

WebKit 内部有个 WKCustomProtocolLoader,负责管理 Web 中资源加载,其中有个私有方法:-(void)connection:(id)arg1 didReceiveData:(id)arg2;

私有头文件可以参见:http://developer.limneos.net/?ios=11.1.2&framework=WebKit.framework&header=WKCustomProtocolLoader.h (opens new window)

当 Web 页面 JS 资源文件请求回来时,这个私有方法会被调用,重写 NSData 即可,示例如下:

CHDeclareClass(WKCustomProtocolLoader)

CHMethod2(void, WKCustomProtocolLoader, connection, NSURLConnection *, connection, didReceiveData, NSData *, data) {
    if ([connection.currentRequest.URL.absoluteString containsString:@"home.4e2b221412.js"]) {
        NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        dataString = [dataString
                      stringByReplacingOccurrencesOfString:@"t.prototype._render=function(e,t){var n=this,r=this.store.state.tree.bubbles;"
                      withString:@"t.prototype._render=function(e,t){window._x_tree = this;var n=this,r=this.store.state.tree.bubbles;"];
        NSData *newData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
        CHSuper2(WKCustomProtocolLoader, connection, connection, didReceiveData, newData);
    } else {
        CHSuper2(WKCustomProtocolLoader, connection, connection, didReceiveData, data);
    }
}

这样一来我们就可以在客户端直接访问 store,想改什么就改什么了。

# Next

  • 一键帮忙收取能量
  • 首页一键获取可收取能量的好友,并一波带走全部好友能量
  • 根据可收取时间,定时自动收取