言成言成啊 | Kit Chen's Blog

蚂蚁森林自动解锁偷能量

发布于2020-07-06 02:51:37,更新于2020-08-10 12:20:20,标签:js open  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

该脚本基于很多大佬开源的作品,先说声感谢。

我写的这个脚本只适用于我自己的手机,我不打算兼容其他手机。如果你要用,可以自己再二次修改,原理都是一样。源代码以及用到的软件放到这里;

2020-07-21更新:

发现bug,即使通过xep来定时处理,autojs脚本也仍然可能出现中断运行的问题。这有可能是autojs的问题,我不知道他的sleep方法是如何实现的,sleep老是不能按期执行,偶尔能定时执行,偶尔又延迟好久执行。

总结了一下原因,还是出在息屏的问题上。长时间息屏导致后台sleep走时延迟。所以我在每天收蚂蚁森林的前一分钟,执行解锁脚本解锁一下,唤醒一下手机,过一分钟之后,再次执行自动脚本。目前是可以运行的。

2020-08-10更新:

今天更新了新版miui系统,但是脚本无法使用了,经过测试,发现xep定时执行是可以的,但是无法自动解锁。

解决办法是,授予电量无限制。新版MIUI会限制在后台启动app,除非给自启动权限,但是如果给了自启动,可能不定时的就会运行脚本,给生活带来困扰。

一、初版本

先放张截图

功能:

  1. 定时解锁
  2. 自动刷步数
  3. 自动收能量
  4. 自动偷能量
  5. 锁屏

全自动蚂蚁森林.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
/**
* 该脚本的思路
* 运行之后,给定权限跟自启动和电源无限制。
* 每天到了下面指定的时间,自动运行。
* 我是android10。偶尔好使,偶尔不好使。
* 可能是android出于安全考虑,限制了息屏后app的运行(有时候时间会运行很慢,或者不走。我尝试将其安装成系统应用,但是还是不好使)
* 不过可以用来每隔10分钟执行一次,这样还是可以的,时间一久,就gg了
*/



//检查是否开启无障碍服务,若未开启则等待开启
auto.waitFor();

//测试机分辨率为1080*2340
//不同像分辨率的机型会按比例缩放
setScreenMetrics(1080, 2340); //不要修改该行代码

var g_help_friend = true;
//六球坐标值
var g_energy_postion = [
[250, 750],
[350, 700],
[450, 650],
[600, 650],
[750, 700],
[850, 750]
];
var hour = 7;
var min = 10;
var sec = 0;


//debug标志 用于测试
const DEBUG = false;

//主程序入口
main();

function addSteps() {
launchApp("小米步数管理");
sleep(500);
id("edtAddSteps").findOne().setText(20000);
sleep(100);
id("btnAddSteps").findOne().click();
console.log("增加步数");
}

/**
* 解锁屏幕
*/
function unlock() {
if (!device.isScreenOn()) { //息屏状态将屏幕唤醒
device.wakeUp(); //唤醒设备
sleep(1000); // 等待屏幕亮起
//miui锁屏滑动不能唤出密码输入 通过下拉通知栏点击时间进入密码解锁
swipe(500, 30, 500, 1000, 300);
sleep(400);
//点击时间
click(100, 120);
sleep(500);
click(555, 1379); //5
sleep(100);
click(244, 1381); //4
sleep(100);
click(224, 1200); //1
sleep(100);
click(541, 1596); //8
sleep(100);
click(541, 1596); //8
sleep(100);
click(224, 1200); //1
sleep(100);
click(244, 1381); //4
sleep(100);
click(555, 1379); //5
sleep(100);
click(544, 1196); //2
sleep(1000);
console.log("自动解锁屏幕");
}
}
/**
*锁定屏幕
*/
function lock() {
KeyCode(26);
console.log("锁屏");
}

/**
* 请求截图权限
*/
function getScreenCapturePermission() { //建议永久开启截图权限,在"取消"按键的上方,部分设备看不见,但是是存在的可以点击
if (!requestScreenCapture()) {
toast("获取截图权限失败,脚本退出");
console.error("获取截图权限失败,脚本退出");
exit();
}
toastLog("获取截图权限成功,等待支付宝启动");
sleep(500);
}

/**
* 注册退出事件
*/
function registerExitEvent() {
var thread = threads.start(function() {
events.observeKey();
events.onKeyDown("volume_down", function(event) {
toast("音量下键被按下,脚本退出");
console.warn("音量下键被按下,脚本退出");
exit();
});
});
return thread;
}

/**
* 寻找支付宝首页
*/
function findHomePage() {
let i = 0;
//尝试5次找到支付宝首页
while (i++ < 5) {
if (text("首页").exists() && text("我的").exists()) break;
back();
sleep(500);
}
if (i < 5)
return true;
else
return false;
}

/**
* 打开支付宝
*/
function openAlipay() { //请确保打开了"Auto.js"的后台弹出界面权限
launchApp("支付宝");
sleep(1000);
//寻找支付宝首页
if (!findHomePage()) { //未找到,退出脚本
toast("寻找支付宝首页失败,脚本退出");
console.error("寻找支付宝首页失败,脚本退出");
exit();
} else { //找到则点击
let item = text("首页").findOnce();
if (!item.selected()) {
let pos = item.bounds();
if (!click(pos.centerX(), pos.centerY())) {
console.error("打开支付宝首页失败,脚本退出");
exit();
}
}
console.log("成功找到支付宝首页");
}
}

/**
* 进入蚂蚁森林
*/
function entranceAntForest() {
//滑动页面找到蚂蚁森林
var item = null,
i = 0;
while (i++ < 5) {
// 使用className和text双重定位
item = className("android.widget.TextView").text("蚂蚁森林").findOnce();
if (item != null) break;
swipe(520, 500, 520, 1500, 500);
sleep(500);
}
if (item == null) {
toast("首页上没有蚂蚁森林,退出脚本");
console.error("首页上没有蚂蚁森林,退出脚本");
exit();
} else {
let pos = item.bounds();
click(pos.centerX(), pos.centerY());
}
//确保进入蚂蚁森林主页
i = 0;
while (i++ < 10) {
if (text("背包").exists() && text("任务").exists()) break;
sleep(1000); //进入蚂蚁森林主页的时间较长,因此循环检测的时间间隔设置为1000ms(default 500ms)
}
if (i >= 10) {
toast("进入蚂蚁森林主页失败,退出脚本");
exit();
} else {
if (DEBUG)
console.log("成功进入蚂蚁森林主页", "用时" + i * 1.0 + "秒");
else
console.log("成功进入蚂蚁森林主页");
}
//收集自己的能量
collectionEnergyByPosition(400); //100ms delay

//确保"查看更多好友"控件出现在屏幕中
item = null;
i = 0;
while (i++ < 10) {
item = text("查看更多好友").findOnce();
if (item != null && item.bounds().height() > 100) break;
swipe(520, 1800, 520, 300, 500);
sleep(500);
}
if (item == null) {
toast("没有找到查看更多好友,退出脚本");
exit();
} else {
let pos = item.bounds();
if (!click(pos.centerX(), pos.centerY())) {
toast("进入好友排行榜失败,退出脚本");
exit();
} else {
//进入好友排行榜
if (DEBUG)
console.log("成功进入好友排行榜", "用时" + i * 0.5 + "秒");
else
console.log("成功进入好友排行榜");
//预留足够的反应时间(default 2000ms)等待进入排行榜页面
//否则会出现排行榜前几个好友检测不到的bug
sleep(2000);

//进入好友排行榜页面收集好友能量
entranceFriendsRank();
}
}
}

/**
* 根据名称查找并点击控件 返回null表示查找失败 返回false表示点击失败 返回true表示成功
* @param {*} click_name 控件名称
* @param {*} match_pos 前缀、后缀还是完全匹配
* @param {*} text_or_desc text还是desc属性
* @param {*} timeout 查找的超时时间
*/
function searchAndClickByName(serach_name, match_pos, text_or_desc, timeout) {
var result = null;
if (match_pos == "prefix") {
if (text_or_desc == "text")
result = textStartsWith(serach_name).findOne(timeout);
else
result = descStartsWith(serach_name).findOne(timeout);
} else {
if (text_or_desc == "text")
result = textEndsWith(serach_name).findOne(timeout);
else
result = descEndsWith(serach_name).findOne(timeout);
}
if (!result) {
let pos = result.bounds();
if (pos.centerX() < 0 || pos.centerY() < 0)
return false;
else
return click(pos.centerX(), pos.centerY());
}
return null;
}

/**
* 通过六球坐标收取(帮收)能量
* @param {*} delay
*/
function collectionEnergyByPosition(delay) {
if (typeof(delay) == "undefined") delay = 0;
for (let i = 0; i < g_energy_postion.length; ++i) {
click(g_energy_postion[i][0], g_energy_postion[i][1]);
sleep(200);
}
}

/**
* 获取截图
*/
function getCaptureImg() {
var img = captureScreen();
sleep(100);
if (img == null || typeof(img) == "undefined") {
toast("截图失败,脚本退出");
console.error("截图失败,脚本退出");
exit();
} else {
return img;
}
}

/**
* 获取有能量成熟的好友
*/
function getHasEnergyFriends() {
var img = getCaptureImg();
var hand = null,
heart = null;

//查找可收取能量的小手 "#1da06d"为深绿色 "#ffffff"为白色
hand = images.findMultiColors(img, "#1da06d", [
[0, -7, "#ffffff"],
[0, 10, "#ffffff"]
], {
region: [1010, 400, 1, 1800],
threshold: 4
});
if (hand != null) {
console.info("找到**可收取**好友");
return [hand, "hand"];
}

if (g_help_friend == true) {
//查找可帮收能量的爱心 "##f99236"为橙色
heart = images.findColor(img, "#f99236", { region: [1000, 400, 10, 1800], threshold: 4 });
if (heart != null) {
console.info("找到**可帮收**好友");
return [heart, "heart"];
}
}
return null;
}

/**
* 检测是否到达排行榜底部
*/
function arriveRankBottom() {
var img = getCaptureImg();
//分别是白色、浅灰色、深灰色
var result = null;
result = images.findMultiColors(img, "#F5F5F5", [
[0, -40, "#FFFFFF"],
[0, 20, "#999999"]
], {
region: [600, 2000],
threshold: 1
});
if (result != null)
return true;
else
return false;
}

/**
* 进入好友排行榜
*/
function entranceFriendsRank() {
var i = 0;
sleep(500);
var epoint = getHasEnergyFriends();

//确保当前操作是在排行榜界面
//不断滑动,查找好友
while (epoint == null) {
swipe(520, 1800, 520, 800, 500);
sleep(500);
epoint = getHasEnergyFriends();
//如果检测到结尾,同时也没有可收能量的好友,那么结束收取
if (epoint == null && arriveRankBottom()) {
toastLog("没有更多好友了");
return true;
}
//如果连续32次都未检测到可收集好友,无论如何停止查找
if (i++ >= 32) {
console.error("程序可能出错, 连续" + i + "次未检测到可收集好友");
return false;
}
}
//找到好友,进入好友森林
if (click(epoint[0].x, epoint[0].y + 20)) {
//确认进入了好友森林
let i = 0;
while (i++ < 10) {
if (text("TA收取你").exists() && text("你收取TA").exists()) break;
sleep(500);
}
if (i < 10) {
if (DEBUG) console.log("成功进入好友森林主页", "用时" + i * 0.5 + "秒");
collectionEnergyByPosition(400); //100ms delay
}
//返回排行榜
back();
}
//递归调用
entranceFriendsRank();
}

/**
* 主函数
*/
function main() {
while (true) {
let date = new Date();
let sleepHour, sleepMin, sleepSec;
if (date.getSeconds() > sec) {
sleepSec = 60 - date.getSeconds() + sec;
} else {
sleepSec = sec - date.getSeconds();
}
if (date.getMinutes() > min) {
sleepMin = 60 - date.getMinutes() + min;
} else if (date.getMinutes() == min) {
if (date.getSeconds() < sec) {
sleepMin = 0;
} else {
sleepMin = 60;
}
} else {
sleepMin = min - date.getMinutes();
}
if (date.getHours() > hour) {
sleepHour = 24 - date.getHours() + hour;
} else if (date.getHours() == hour) {
if (date.getMinutes() < min) {
sleepHour = 0;
} else {
sleepHour = 24;
}
} else {
sleepHour = hour - date.getHours();
}
if (sleepHour > 0) {
sleepHour--;
}
if (sleepMin > 0) {
sleepMin--;
}
let message = "休眠" + sleepHour + "小时" + sleepMin + "分钟" + sleepSec + "秒后运行";
toast(message);
console.log(message);

sleep(sleepHour * 60 * 60 * 1000 + sleepMin * 60 * 1000 + sleepSec * 1000);



unlock();
//添加步数
addSteps();
//获取截图权限
getScreenCapturePermission();
//注册"音量下键按下退出脚本"事件
//var exit_event = registerExitEvent();
//等待退出事件子线程执行
//exit_event.waitFor();
//打开支付宝
openAlipay();
//进入蚂蚁森林
entranceAntForest();
lock();
}
}

然后,我将上述代码打包成了app。如下图。

二、Bug

短时间后台运行,autojs是可以自动解锁完成一系列功能的。

长时间后台运行,就不行了。即使你给了所有权限、自启动、电源无限制,也是没用的。这应该是高版本android对后台app的一些限制。

我看网上说,用tasker,我也试了,跟autojs同样的问题。

三、改进

通过xposed edge pro添加定时任务,定时启动上述脚本app。然后脚本app再执行解锁、刷步数、收能量、锁屏一系列操作。

四、致谢

  1. 蚂蚁森林自动收取能量
  2. 云养鸡种树

感谢以上大佬!

发布:2020-07-06 02:51:37
修改:2020-08-10 12:20:20
链接:https://meethigher.top/blog/2020/auto-antforest/
标签:js open 
付款码 打赏 分享
若无法评论请科学上网
Shift+Ctrl+1 可控制工具栏