1.题库,我也是漂的网上大佬的,自己去网上扒吧,扒下来后,按我之前的教程处理成{wenti:daan,wenti:daan}。
2.出现验证码会有振动,个人觉得不是很大声,害怕有上课刷的吓到先说一声,代码里可以改。
3.出现验证码,但是答题时间是不会停的,所以需要尽快输入。
4.需要注意,不同手机的控件信息可能不同,如果不能用,需要改
"ui";
var appName = " SSXX";
ui.statusBarColor("#FF4FB3FF")
ui.layout(
<drawer id="drawer">
<vertical>
<appbar>
<toolbar id="toolbar" bg="#ff4fb3ff" title="{
{appName}}" />
<button id="exit" text="退出" color="#ffffff" bg="#FF4FB3FF" />
</appbar>
<vertical gravity="center" layout_weight="1">
<frame>
{
/* */}
<viewpager h="84" id="pager">
<vertical>
<card w="*" h="68" margin="10 8" cardCornerRadius="6dp"
cardElevation="2dp" gravity="center">
<linear>
<vertical margin="10" layout_gravity="center_vertical" layout_weight="1">
<text id="name" size="18" color="#444444" text="请确认答题界面在主界面" />
<text id="name" size="14" color="#444444" text="请开启无障碍服务和悬浮窗" />
</vertical>
</linear>
</card>
</vertical>
<vertical>
<card w="*" h="68" margin="10 8" cardCornerRadius="6dp"
cardElevation="2dp" gravity="center">
<linear>
<vertical margin="10" layout_gravity="center_vertical" layout_weight="1">
<text id="imei" textIsSelectable="true" size="14" color="#444444" text="答题过程中进行其他操作会导致脚本停止" />
<text id="Etime" size="12" text="验证码需要手动输入,注意验证码出现时答题时间不会暂停" />
</vertical>
</linear>
</card>
</vertical>
</viewpager>
</frame>
<tabs w="40" id="tabs" tabIndicatorColor="#777777" bg="#cfcfcf" h="2" />
<vertical padding="10 6 0 6" bg="#ffffff" w="*" h="auto" margin="0 5" elevation="1dp">
<Switch id="autoService" w="*" checked="{
{auto.service != null}}" textColor="#666666" text="无障碍服务" />
<View h="5" />
<Switch id="xuanfuchuang" w="*" textColor="#666666" text="悬浮窗(不确定是否开启的点击->)" />
</vertical>
<vertical margin="0 5" bg="#ffffff" elevation="1dp" padding="5 5 10 5" w="*" h="auto">
<linear>
<checkbox id="ZDcheck" text="振动提醒(验证码出现)" layout_weight="1" />
<text text="振动声音大小↓" />
</linear>
<linear>
<seekbar id="DYseekbar" max="50" layout_weight="1" />
<text gravity="center" id="ZDlimit" />
</linear>
<View h="5" />
</vertical>
<vertical>
<text layout_weight="1" size="19" color="#222222" text="设置" />
<horizontal>
<radiogroup layout_weight="1" id='pianmu'>
<radio w="auto" checked="true" id="yx" text='英雄篇'></radio>
<radio w="auto" id="fx" text='复兴篇'></radio>
<radio w="auto" id="cx" text='创新篇'></radio>
<radio w="auto" id='xn' text="信念篇"></radio>
</radiogroup>
<radiogroup layout_weight="1" id='xunhuan'>
<radio w="auto" checked="true" id='a' text='循环5次'></radio>
<radio w="auto" id='b' text='10次'></radio>
<radio w="auto" id='c' text='20次'></radio>
<radio w="auto" id='d' text='每次提交后询问'></radio>
</radiogroup>
<input hint = "自定义" id='userin'> </input>
</horizontal>
</vertical>
<linear>
<text layout_weight="1" size="19" color="#222222" text="日志" />
<button id="tolog" h="40" text="查看日志" style="Widget.AppCompat.Button.Borderless.Colored" />
</linear>
<text paddingLeft="5" size="16" id="oneLog" />
<card w="*" h="*" margin="10 8" cardCornerRadius="6dp"
cardElevation="2dp" gravity="center">
<linear>
<vertical margin="10" layout_gravity="center_vertical" layout_weight="1">
<text id="n" size="18" color="#444444" text="CSDN:头发浓密的萌新的博客" />
<text autoLink="web" text="https://blog.csdn.net/tfnmdmx" />
<text id="a" size="12" color="#555555" gravity="right" text="感谢点赞评论收藏关注!" />
<text id="m" size="18" color="#444444" text="本程序只供交流学习" />
<text id="e" size="12" color="#ff0000" gravity="right" text="请勿用作其他用途 " />
</vertical>
</linear>
</card>
<list bg="#ffffff" elevation="1dp" h="*" id="logList">
<linear>
<text size="100" textColor="#555555" text="{
{time}} " />
<text size="44" text="{
{message}}" />
</linear>
</list>
</vertical>
<button id="start" text="开始运行" tag="ScriptTag" color="#ffffff" bg="#FF4FB3FF" foreground="?selectableItemBackground" />
</vertical>
</drawer>
);
//设置滑动模式
ui.logList.setOverScrollMode(2);
//设置滑动页面的标题
ui.pager.setTitles(["", ""]);
//让滑动页面和标签栏联动
ui.tabs.setupWithViewPager(ui.pager);
//无障碍开关监控
ui.autoService.setOnCheckedChangeListener(function (widget, checked) {
if (checked && !auto.service) {
app.startActivity({
action: "android.settings.ACCESSIBILITY_SETTINGS"
});
}
if (!checked && auto.service) auto.service.disableSelf()
ui.autoService.setChecked(auto.service != null)
});
ui.xuanfuchuang.setOnCheckedChangeListener(function (widget, checked) {
if (checked) {
app.startActivity({
packageName: "com.android.settings",
className: "com.android.settings.Settings$AppDrawOverlaySettingsActivity",
data: "package:" + context.getPackageName(),
});
}
// 没有悬浮窗权限,提示用户并跳转请求
toast("本脚本需要悬浮窗权限来显示悬浮窗");
//if(!checked&&auto.service)auto.service.disableSelf()
//ui.xuanfuchuang.setChecked(auto.service!=null)
});
//存储
ui.DYseekbar.setOnSeekBarChangeListener({
onProgressChanged: function (v, i, fromUser) {
ui.run(() => {
ui.ZDlimit.setText("" + i * 40) })
storages.create(appName).put("ZDlimit", i * 10)
//toast(ui.ZDlimit.getText())
}
})
//存储器
ui.DYseekbar.setProgress(storages.create(appName).get("ZDlimit", 200) / 10)
//回到本界面时,resume事件会被触发
ui.emitter.on("resume", () => {
// 此时根据无障碍服务的开启情况,同步开关的状态
ui.autoService.checked = auto.service != null;
// ui.xuanfuchuang.checked = auto.service != null;
});
//禁止返回退出脚本
ui.emitter.on("back_pressed", function (event) {
if (workThread && workThread.isAlive()) {
backTag = true;
toast("为防止脚本自动退出,脚本运行时不可返回退出软件");
event.consumed = true;
}
})
ui.tolog.click(() => {
app.startActivity("console")
})
ui.start.click(() => {
ui.start.setText("停止运行");
workThread = threads.start(function () {
try {
clearLog()
if (!auto.service) toast("请先打开无障碍服务");
else workMain()
} catch (e) {
if (!e.javaException instanceof java.lang.InterruptedException)
console.error("运行出错:" + e.toString())
} finally {
ui.run(function () {
ui.start.setText("开始运行")
threads.start(main)
});
}
});
});
ui.exit.click(() => {
log("停止运行");
threads.shutDownAll()
exit()
});
//var thread = threads.start(function() {
var 多选 = 0 //1是0否
var 选项 = ["初", "始", "化", "用"]
function 设置悬浮窗(悬浮窗位置x, 悬浮窗位置y, 是1否0开启控制栏) {
var 悬浮窗 = floaty.window(
//floaty.rawWindow
<frame gravity="center" bg="#CC999999">
<text id="text" textColor="#ffffffff">开启悬浮窗</text>
</frame>
);
悬浮窗.setPosition(悬浮窗位置x, 悬浮窗位置y)
if (是1否0开启控制栏 == 1) {
悬浮窗.setAdjustEnabled(true)
}
return 悬浮窗
}
/*
*好像相当于控制台
*在悬浮窗和日志里打印信息
*/
function 提示文本(_text) {
ui.run(function () {
悬浮窗.text.setText(_text);
});
log(_text)
}
function 加载题库(path) {
//path = "/storage/emulated/0/脚本/cx.js"
var 题库 = files.read(path)//题库里有一个题目分行,导致错误,需要手动处理
pattern = /[`~!@#$^&*()=|';'“”\\\.<>\/?~!@#¥……&*()——|【】';:'。,、?\s]/g;
题库 = 题库.replace(pattern, "")
//log(题库)
题库 = eval("(" + 题库 + ")");
return 题库
}
/*
*读取题目
*处理题目
*/
function 读取题目() {
多选 = 0
控件 = className("android.view.View").find();
题目 = ''
jj = 0
for (i = 0; i < 控件.length; i++) {
控件里的文字 = 控件[i].text();
if (控件里的文字 != "") {
题目 += 控件里的文字;
//log(控件[i].depth()+","+控件[i].indexInParent()+","+控件[i].text())
//多选题比单选多一行checkbox-group
if (控件里的文字.indexOf('学】') > -1 || 控件里的文字.indexOf('学]') > -1) {
break
}
}
}
if (题目.indexOf("多选题") != -1) {
//【单选题】【多选题】
多选 = 1
}
if (题目.indexOf("题】") != -1) {
//【单选题】【多选题】
var index = 题目.indexOf("题】")
题目 = 题目.substring(index + 2, 题目.length)
}
if (题目.indexOf("【出题:武汉大学】") != -1) {
var index = 题目.indexOf("【出题:武汉大学】")
题目 = 题目.substring(0, index)
}
if (题目.indexOf("[题目来源:") != -1) {
//[题目来源:湘潭大学西安交通大学上海交通大学]
var index = 题目.indexOf("[题目来源:")
题目 = 题目.substring(0, index)
}
//对获取的题目进行处理,去除所有特殊字符
pattern = /[`~!@#$^&*()=|{}':;'“”,\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;
题目 = 题目.replace(pattern, "")
log(题目)
return 题目
}
function 提取选项() {
if (!多选) {
for (i = 0; i < 4; i++) {
选项[i] = ''
if (className("RadioButton").depth("24").indexInParent(i).findOnce())
className("RadioButton").depth("24").indexInParent(i).findOne().children()
.forEach(function (child) {
//log(child.className());
if (child.className() == "android.view.View") {
if (child.text() != "") {
if (选项[i] != child.text())
选项[i] += child.text()
//log(child.text());
}
else {
child.children()
.forEach(function (child) {
// log(child.className());
if (child.text() != "") {
if (选项[i] != child.text())
选项[i] += child.text()
//log("!" + child.text());
}
});
}
}
});
//log("++++" + 选项[i]);
}
}
else {
for (i = 0; i < 4; i++) {
选项[i] = ''
if (className("CheckBox").depth("23").indexInParent(i).findOnce())
className("CheckBox").depth("23").indexInParent(i).findOne().children()
.forEach(function (child) {
if (child.className() == "android.view.View") {
// log(child.className());
if (child.text() != "") {
if (选项[i] != child.text())
选项[i] += child.text()
// log(" " + child.text());
}
else {
child.children()
.forEach(function (child) {
if (child.className() == "android.view.View") {
// log(child.className());
if (child.text() != "") {
if (选项[i] != child.text())
选项[i] += child.text()
//log("!" + child.text());
}
}
});
}
}
});
}
}
pattern = /[`~!@#$^&*()=|{}':;'“”,\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;
for (i = 0; i < 4; i++) {
提示文本("选项" + i + 选项[i] + " ");
选项[i] = 选项[i].replace(pattern, "")
}
}
/*
*匹配答案
* 题库中[第i个题目].indexof(题目)>-1,表示匹配到问题
* 返回答案
*/
function 匹配答案(题库, 题目) {
i = 0
flag = 0
while (Object.keys(题库)[i]) {
if (Object.keys(题库)[i].indexOf(题目) > -1) {
flag = 1
var 答案 = 题库[Object.keys(题库)[i]]
return 答案
}
i++;
}
if (flag == 0) 提示文本("没有匹配到问题,自行作答,百度搜索") //没有写百度搜索
return -1
}
function 点击答案(答案) {
if (答案 == -1) {
if (className("android.widget.RadioButton").depth("24").indexInParent(1).findOnce()) {
className("android.widget.RadioButton").depth("24").indexInParent(1).findOnce().click()
toast("无匹配,默认点击第2个")
}
/* else if (className("android.widget.RadioButton").depth("25").indexInParent(1).findOnce()){
className("android.widget.RadioButton").depth("25").indexInParent(1).findOnce().click()
提示文本("点击出错");
return 0
} */
else {
toast("默认全选")
for (j = 0; j < 4; j++) {
sleep(1000 + random(0, 3000))
随机位置x = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerX() + random(0, 300)
随机位置y = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)
}
}
}
else {
if (!多选) {
for (j = 0; j < 4; j++) {
if (答案.indexOf(选项[j]) > -1) {
//第一次开始有可能点错//多选匹配
//答案相近,即前面的选项含有答案的文字就会被点击,必须提取完整答案
sleep(1000 + random(0, 3000))
随机位置x = className("android.widget.RadioButton").depth("24").indexInParent(j).findOnce().bounds().centerX() + random(0, 100)
随机位置y = className("android.widget.RadioButton").depth("24").indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)
break
}
}
}
else if (多选 == 1) {
for (j = 0; j < 4; j++) {
if (答案.indexOf(选项[j]) > -1) {
toast("点击" + j);
随机位置x = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerX() + random(0, 100)
随机位置y = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)
sleep(1000 + random(0, 3000))
}
}
}
}
return 1
}
function vibrate(duration, times, delay) {
if (delay == null) delay = 0
if (times == null) times = 1
for (i = 0; i < times; i++) {
device.vibrate(duration);
sleep(delay)
}
}
function 检测验证码(){
//toast("检测验证码")
if (text("验证码").exists()) {
//会影响下一道题
if(ui.ZDcheck.isChecked())
vibrate(ui.ZDlimit.getText(), 3, 200)
else{
toast("zahuishia")
}
alert("验证码出现啦!救命啊!");
sleep(10000)
toast("还有5s")
sleep(5000)
}
}
function main() {
pm = -1
xh = -1
if (ui.yx.isChecked()) pm = 1;
if (ui.fx.isChecked()) pm = 2;
if (ui.cx.isChecked()) pm = 3;
if (ui.xn.isChecked()) pm = 4;
if (ui.a.isChecked()) xh = 1;
if (ui.b.isChecked()) xh = 2;
if (ui.c.isChecked()) xh = 3;
if (ui.d.isChecked()) xh = 4;
/*toast('pm='+pm+'pm=')//322
toast('xd='+xh+'pm=')
toast(ui.ZDlimit.getText())*/
悬浮窗 = 设置悬浮窗(100, 100, 0)
提示文本("加载悬浮窗");
launch("com.tencent.mm");
提示文本("跳转微信");
提示文本("加载题库中...");
switch (pm) {
case 1: path = "/storage/emulated/0/脚本/yx.js"; pmtext = "英雄篇"; pmx = random(80, 500); pmy = random(900, 1100); break;
case 2: path = "/storage/emulated/0/脚本/fx.js"; pmtext = "复兴篇"; pmx = random(560, 1000); pmy = random(900, 1100); break;
case 3: path = "/storage/emulated/0/脚本/cx.js"; pmtext = "创新篇"; pmx = random(80, 500); pmy = random(1200, 1400); break;
case 4: path = "/storage/emulated/0/脚本/xn.js"; pmtext = "信念篇"; pmx = random(560, 1000); pmy = random(1200, 1400); break;
default: path = "/storage/emulated/0/脚本/yx.js";
}
题库 = 加载题库(path)
提示文本(pmtext + "-题库加载完成");
sleep(3000)
提示文本("开始答题");
if (text("返回").exists())
{
click("返回")
sleep(2000)
}
click(pmx, pmy)
sleep(2000)
switch (xh) {
case 1: 循环 = 5; break;
case 2: 循环 = 10; break;
case 3: 循环 = 20; break;
case 4: 循环 = 1; break;
default: 循环 = 1;
}
while (循环--) {
if (text("返回").exists())
{
click("返回")
sleep(2000)
}
click(pmx, pmy)
sleep(2000)
while (1) {
检测验证码()
题目 = 读取题目()
检测验证码()
提取选项()
检测验证码()
提示文本("正在匹配答案");
答案 = 匹配答案(题库, 题目)
检测验证码()
sleep(1000)
提示文本("答案:" + 答案)
if (点击答案(答案)) {
检测验证码()
sleep(2000)
if(text("下一题").exists())
click("下一题")//一直可点,未作答点击无反应
else{
if ( text("提交").exists()) {
sleep(2000)
click("提交")//一直可点,未作答点击无反应
提示文本("提交")
sleep(2000)
break
}
检测验证码()
}
}
sleep(4000)
if (题目.indexOf("答对题目数") > -1) {
sleep(2000)
break
}
}
if(循环==0||xh == 4){
循环 = confirm("要继续刷题吗?");
if (循环) {
循环 = 1
sleep(2000)
while (!click("返回"))
toast("返回")
sleep(2000)
}
else {
toast("脚本已停止")
threads.shutDownAll()
exit()
break
}
}
}
}
//});
//目标是写每隔10s检测是否有验证码,有就暂停脚本,之后继续脚本
/* var thread_yanzhengma = threads.start(function(){
//设置一个空的定时来保持线程的运行状态
setInterval(function(){
toast("检测验证码")
if (text("验证码").exists()) {//会影响下一道题
if(ui.ZDcheck.isChecked())
vibrate(ui.ZDlimit.getText(), 3, 200)
alert("验证码出现啦!救命啊!");
sleep(10000)
toast("还有5s")
sleep(5000)
}
}, 10000);
}); */
/*
//检测出错,一分钟页面都没变,视为出错,随机点击可能位置
var thread_tijiao = threads.start(function(){
if (n >= 20 && text("提交").exists())
//设置一个空的定时来保持线程的运行状态
setInterval(function(){}, 1000);
}); */
/* if (上次答案 == 答案) {
if (!多选) {
toast("默认点击第2个")
className("android.widget.RadioButton").depth("24").indexInParent(1).findOnce().click()
}
else {
toast("默认全选")
for (j = 0; j < 4; j++) {
sleep(1000 + random(0, 3000))
随机位置x = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerX() + random(0, 300)
随机位置y = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)
}
}
} */
希望路过的大佬可以指点一下
一,怎么把退出放到软件名字那一栏的左边(即整个页面的左上角),网上查到的只有菜单栏的配置,就是三个点,是不是不能更改成其他的?
二,对于识别验证码的问题,我试了调用百度识图,识别效果挺差的,现在想试试联众,有知道的朋友可以指点一下吗?
三,对于多线程问题,本来准备写一个子线程间隔时间一直检测的,但是由于初次接触,还不能很好的使用线程,导致在子线程检测到验证码后,主线程(可能是)仍然会继续运行,望大佬指点。
本次更新增加了ui界面,也使用了一点点多线程,在学习更多知识之后会写一些总结。