滚动阅读


title: 滚动阅读 date: 2019-10-25 20:04:22

tags:

初步构思

  1. 定时任务启动
  2. 滑到面板桌面(从常规桌面上滑)
  3. 点击礼盒图标(右上角,测量位置)
  4. 点击完成相关任务(位置)
  5. 自动唤醒京东读书 app
  6. 点击图书(位置)
  7. 自动翻页(swipe)
  8. 完成后返回打卡页面
  9. 点击完成打卡(位置)

新增:

  1. 时间统计(共阅读了多久)
  2. 页数统计(共阅读了多少页)

防检测

自动翻页位置

  1. 滑动翻页(swipe) Math.random
  2. 点击翻页(touch),时间和位置都随机
  3. 映射音量键翻页

该机分辨率为 1440*720

下一页触摸区域在 x(480-720),y(0-1440)

规则:

30 分钟阅读 300 页,则每分钟阅读 10 页,至少 6 秒阅读完一页.

1
6000 * (Math.random() + 1);

每页最少 6 秒,最多 12 秒不到.

每 300 页最少 30 分钟.最多 60 分钟不到.

随机时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var initTime = 6000 * (Math.random() + 0.33333);
if (initTime < 6000) {
initTime += 4000;
}
//或者

function iTime() {
var initTime = 6000 * (Math.random() + 0.33333);
if (initTime < 6000) {
return (initTime += 4000);
}
return initTime;
}

iTime();

每页最少 2 秒,最多 8 秒不到.

每 300 页最少不到 16 分钟.最多 40 分钟不到.

定时运行脚本

点击脚本右边的菜单按钮->更多->定时任务设置定时运行脚本.注意必须保持 Auto.js 后台运行(自启动白名单、电源管理白名单等),不可加锁屏密码.

脚本的开头使用 device.wakeUp()来唤醒屏幕

1
2
3
4
5
//# 启动app
app.launchApp("京东读书");

//暂停运行5秒
sleep(5000);

气泡信息toast(message)

注意,信息的显示是”异步”执行的,并且,不会等待信息消失程序才继续执行。如果在循环中执行该命令,可能出现脚本停止运行后仍然有不断的气泡信息出现的情况

官方貌似说了会实时显示进度,那么下面的统计就不需要了.

这里可以显示已经看了几页(估计得写个函数),看具体是怎么翻页了

1
2
3
4
5
如果触发一次, 就次数`total += 1`;
if (total == 300) {
//toast('看完300页了,准备打卡去')
//建议此时不停,不知道时间够不够,继续刷一会
}
1
2
3
4
5
6
7
if (total >= 300 && totalTime >= 30 * 6000) {
//条件满足,停止刷页
stop();
//跳转打卡页面
} else {
//继续刷页
}

立即停止exit()

console.show()

显示控制台。这会显示一个控制台的悬浮窗(需要悬浮窗权限)。

text {string} | {Object}要打印到控制台的信息,相当于 log(text)。

基于坐标的触摸模拟

要获取要点击的位置的坐标,可以在开发者选项中开启”指针位置”。

setScreenMetrics(width, height)

设置脚本坐标点击所适合的屏幕宽高.

如果脚本运行时,屏幕宽度不一致会自动放缩坐标.

安卓 7.0 以上的触摸和手势模拟

click(x, y)

模拟点击坐标(x, y),并返回是否点击成功。只有在点击执行完成后脚本才继续执行。

使用该函数模拟连续点击时可能有点击速度过慢的问题,这时可以用press()函数代替。

press(x, y, duration)

duration: {number} 按住时长,单位毫秒

模拟按住坐标(x, y), 并返回是否成功。只有按住操作执行完成时脚本才会继续执行。

如果按住时间过短,那么会被系统认为是点击;如果时长超过 500 毫秒,则认为是长按。

swipe(x1, y1, x2, y2, duration)

x1 {number} 滑动的起始坐标的 x 值

y1 {number} 滑动的起始坐标的 y 值

x2 {number} 滑动的结束坐标的 x 值

y2 {number} 滑动的结束坐标的 y 值

duration {number} 滑动时长,单位毫秒

模拟从坐标(x1, y1)滑动到坐标(x2, y2),并返回是否成功。只有滑动操作执行完成时脚本才会继续执行。

随机数 random

random(min, max)

min {number} 随机数产生的区间下界

max {number} 随机数产生的区间上界

返回 {number}

返回一个在[min...max]之间的随机数(正整数)。例如random(0, 2)可能产生 0, 1, 2。

random()

返回 {number}

返回在[0, 1)的随机浮点数。

device.wakeUp()

唤醒设备。包括唤醒设备 CPU、屏幕等。可以用来点亮屏幕。

device.wakeUpIfNeeded()

如果屏幕没有点亮,则唤醒设备。

按键模拟

实体按键模拟依赖 root 权限,故放弃.

基于控件的操作

推荐使用auto()函数来确保无障碍服务已启用.

auto([mode])

检查无障碍服务是否已经启用,如果没有启用则抛出异常并跳转到无障碍服务启用界面;同时设置无障碍模式为 mode。

如果不加 mode 参数,则为正常模式。

建议使用auto.waitFor()auto.setMode()代替该函数,因为auto()函数如果无障碍服务未启动会停止脚本;而auto.waitFor()则会在在无障碍服务启动后继续运行。

auto.waitFor()

检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。

点击文本click(text[, i])

text {string} 要点击的文本

i {number} 如果相同的文本在屏幕中出现多次,则 i 表示要点击第几个文本, i 从 0 开始计算

该函数可以点击大部分包含文字的按钮。例如微信主界面下方的”微信”, “联系人”, “发现”, “我”的按钮。

通常与 while 同时使用以便点击按钮直至成功。例如:

1
while (!click("扫一扫"));

UiSelector.exists()

返回 {Boolean}

判断屏幕上是否存在控件符合选择器所确定的条件。

例如要判断某个文本出现就执行某个动作,可以用:

1
2
3
if (text("某个文本").exists()) {
//要支持的动作
}

暂停 sleep()

1
2
//暂停1秒
sleep(1000);

选取控件

一般软件的界面是由一个个控件构成的,例如图片部分是一个图片控件(ImageView),文字部分是一个文字控件(TextView);同时,通过各种布局来决定各个控件的位置,例如,线性布局(LinearLayout)里面的控件都是按水平或垂直一次叠放的,列表布局(AbsListView)则是以列表的形式显示控件。

控件有各种属性,包括文本(text), 描述(desc), 类名(className), id 等等。我们通常用一个控件的属性来找到这个控件,例如,想要点击 QQ 聊天窗口的”发送”按钮,我们就可以通过他的文本属性为”发送”来找到这个控件并点击他,具体代码为:

1
2
var sendButton = text("发送").findOne();
sendButton.click();

在这个例子中, text(“发送”)表示一个条件(文本属性为”发送”),findOne()表示基于这个条件找到一个符合条件的控件,从而我们可以得到发送按钮 sendButton,再执行 sendButton.click()即可点击”发送”按钮。

果一个控件是图片控件.我们注意到这个图标的 desc(描述)属性为”搜索”,那么我们就可以通过 desc 属性来定位这个控件,得到点击搜索图标的代码为:

1
desc("搜索").findOne().click();

另外,对于这个搜索图标而言,id 属性也是唯一的,我们也可以用 id(“action_search”).findOne().click()来点击这个控件。如果一个控件有 id 属性,那么这个属性很可能是唯一的.

i_reader_folder

定时器 Timers

setTimeout()

与 web 端用法一致.但是使用了一个不同的内部实现,它是基于 Android Looper-Handler 消息循环机制构建的。其实现机制与 Node.js 比较相似.

setInterval(callback, delay[,…args])

callback {Function} 当定时器到点时要调用的函数。

delay {number} 调用 callback 之前要等待的毫秒数。

…args {any} 当调用 callback 时要传入的可选参数。

因为定时器是异步执行,另外 delay 只能是 number,那么不采用这种方案.

刷页函数

1
2
3
function turnPage(){
...
}

准备工作

先打开京东读书,登录账号

点击书城-免费-点击一本书-加入书架-(多加几本)

方案一: 点击翻页

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
//检查无障碍服务开启情况
auto.waitFor();
//显示控制台
console.show();
//设置脚本适合的宽高
setScreenMetrics(720, 1440);
//打开京东读书app
app.launchApp("京东读书");
toast("开始打卡");

//等待启动
sleep(2000);

//跳过
if (text("跳过").exists()) {
//点击控件
text("跳过").findOne().click();
sleep(2000);
}

//检测升级
if (text("下次再说").exists()) {
//点击控件
text("下次再说").findOne().click();
sleep(2000);
}

//点击控件,跳转书架
id("main_tab_bookshelf").findOne().click();
sleep(1000);

//准备开始图书

//随机时间
var initTime = 6000 * (Math.random() + 0.33333);
if (initTime < 6000) {
initTime += 4000;
}

这里有问题

应该阅读到末尾结束,出现关闭阅读.点击关闭阅读.删除第一本.重新打开一本,开始阅读.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//已读完时,左上角出现关闭阅读
if (text("关闭阅读").exists()) {
//点击控件
text("关闭阅读").findOne().click();
sleep(2000);
//长按第一本书,左下角删除,弹出确认删除,点击第二个删除.sleep(2000),右上角完成,继续阅读()
let index;
deleteBook();
//继续阅读
//删掉之后,加上已阅读200页,重新开始,又会阅读300页.
this.index = index;

readBook();
} else {
//执行自动阅读
readBook();
}

开始阅读-阅读完-跳出阅读-删除-重新开始阅读

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
//执行阅读主步骤
mianStep()

function mianStep(){
readeBook()
if(text("关闭阅读").exists()){
//点击控件
text("关闭阅读").findOne().click()
sleep(2000)
//长按第一本书,左下角删除,弹出确认删除,点击第二个删除.sleep(2000),右上角完成,继续阅读()
let index
deleteBook()
//继续阅读
//删掉之后,加上已阅读200页,重新开始,又会阅读300页.
this.index = i
mianStep()
}

//自动阅读
function readBook(){
toast("开始阅读")
//选择第一本
id("i_reader_folder").indexInParent(0).findOne().click()
sleep(3000)
//执行点击
clickPage()
}

//点击阅读
function clickPages(){
//点击300页
for(let {i=0}=index; i<300; i++){
randomClick()
//间隔时间
sleep(initTime)
}
}

//定时器版
// for(var i=0; i<5; i++){
// setTimeout(randomClick(),initTime)
// }

//随机点坐标
function randomClick(){
//随机坐标,各缩减20px,防止误触
x = random(500, 700)
y = random(20, 1420)
//点击随机坐标区域翻页
click(x, y)
}


//删除已读数目
function deleteBook(){
//长按图书,坐标就是第一本书的位置
//press(x, y, 1500)
id("i_reader_folder").indexInParent(0).findOne().longClick()
//删除图书
text("删除").findOne().click()
//要确认删除了
id("confirm").findOne().click()
//右上角完成
text("完成").findOne().click()
}



//点击打卡文本
click(text["立即打卡"])

//打印结束
toast("打卡结束")

方案二: 滑动翻页