编写脚本
将VSCode连接好手机上的autoX以后,打开”通用脚本框架v1.1.js“,复制一份,改名为“yanghao.js”
下面我们使用**通用脚本框架模版**,来编写一个简单的DY养号脚本。
# 设置包名
因为要操作某音,所以要先在全局变量里,设置程序名和包名

# 设置测试参数
因为是在调试开发阶段,所以要模拟脚本运行的参数。
这个参数,要从redis数据库里,复制全部参数,并**保存到myTaskInfo**这个全局变量里。

从通用模版的大约135行左右开始,有一大段代码被屏蔽了。
这是一段测试代码。在开发的时候,要解除屏蔽。
正式发布的时候,仍然要屏蔽或者删除掉!
测试区域的代码如下:
```javascript
// ////////脚本运行参数示例:
myTaskInfo = {
"task_id": "1",
"module_id": "1",
"module_name": "yanghao",
"module_group_id": "1",
"module_param": {
"watch_num": "3",
"watch_min": "3",
"watch_max": "5",
"layuiTreeCheck_1": "1",
"layuiTreeCheck_9B2EDAE5239A1B55": "9B2EDAE5239A1B55",
"layuiTreeCheck_CE36CD237F859F17": "CE36CD237F859F17"
},
"custom_param": {
"is_limited_time": "0",
"limit_time": "600",
"wait_time_min": "1",
"wait_time_max": "3",
"delay_min": "1",
"delay_max": "3"
},
"module_url": "http://new-cloud.feiyunjs.cn/components/Module/aweme/yanghao.js",
"mode": "1",
"start_time": "",
"task_source": 0,
"state": "1",
"imei": "9B2EDAE5239A1B55",
"device_number": "1B55",
"callback_data": "",
"remarks": "",
"add_time": "2023-04-21 20:33:42",
"update_time": "",
"replenish_num": 0,
"complete_num": 0
}
moduleParam = myTaskInfo.module_param;
myCustomParam = myTaskInfo.custom_param;
if (moduleParam) {
// console.log('用户任务参数:' + JSON.stringify(moduleParam));
for (var item in moduleParam) {
myModuleParam[item] = moduleParam[item];
}
}
// 判断应用是否安装
if (getAppName(myApp.packageName)) {
main();
} else {
console.error('指定应用并未安装:' + myApp.appName);
}
```
这里我们再来捋一遍创建和下发任务的流程。
首先在后台创建一个脚本任务,将任务信息,保存在redis表里。
被控端从后台取到任务后,就获得了redis的任务数据。
在脚本里,对任务信息json进行解析和重构。
然后再执行脚本的逻辑。
脚本任务完成后,通过api接口,将执行结果回传给redis,即修改redis里的任务信息。
# 编写养号代码
接下来,在core()方法的死循环里,编写核心的养号代码。
我们来写一个简单的例子
```javascript
function core() {
let isStop = false; //完成任务后是否停止
let isFail = false //是否失败
let delay = random(Number(myCustomParam.delay_min), Number(myCustomParam.delay_max));
//--------------------------------------------------------------------------------------------------------------------------
let version = common.getPackageVersion(myApp.packageName);
log("目标App版本:" + version);
// 启动应用
launch(myApp.packageName);
sleep(10000);
common.clickNodeEx('text', '始终允许|允许', delay);
log('应用启动结果:', currentActivity());
log('需浏览作品 ' + myModuleParam.watch_num + ' 个');
while (true) {
myApp.activity = currentActivity();
// console.log("页面地址:" + myApp.activity)
if (isFail) {
common.modifyOneTask(myTaskInfo.task_id, 4, JSON.stringify(myTaskInfo), JSON.stringify(info)); //更新任务
break; //跳出循环
} else if (isStop) {
// home();
let data = {};
console.info(data);
common.modifyOneTask(myTaskInfo.task_id, 3, JSON.stringify(myTaskInfo), JSON.stringify(data)); //更新任务
break; //跳出循环
};
// !!!这里编写脚本的核心代码
// // 简单示例:
// for (let index = 0; index < 100; index++) {
// log(index);
// sleep(500);
// // 当满足设定条件时,停止脚本执行,告诉后台任务成功/失败
// if (index > 50) {
// isStop = true; //脚本执行成功
// break;
// }
// }
// 翻页浏览作品
for (ii = 0; ii < Number(myModuleParam.watch_num); ii++) {
swipe(random(device.width / 3, device.width / 2), random(device.height * 9 / 10, device.height * 8 / 10), random(device.width / 3, device.width / 2), random(device.height * 1 / 10, device.height * 0.5 / 10), random(500, 1000));
let watchTime = random(Number(myModuleParam.watch_min), Number(myModuleParam.watch_max));
log('浏览第 ' + (ii + 1) + ' 个作品 ' + watchTime + ' 秒');
sleep(watchTime * 1000);
};
isStop = true; //脚本执行成功
};
};
```
完整的脚本代码如下:
```javascript
// 保持脚本运行
var ID = setInterval(() => { }, 1000), myApp = {}, myTaskInfo = {}, myModuleParam = {}, moduleParam = [], myCustomParam = {}, myNode = {}, info = {};
myApp.activityArr = new Array(); //存放页面地址
requiresAutojsVersion(635); //此脚本需要Auto.js版本达到指定版本才能运行
myApp.appName = "抖音";
myApp.packageName = "com.ss.android.ugc.aweme";
//--------------------------------------------------------------------------------------------------------------------------
// 加载外部模块
let modulePath = files.cwd() + '/common.js';
// log(modulePath);
let common = {};
if (files.exists(modulePath)) {
log('引用公共模块');
common = require(modulePath);
// var common = require('common.js');
// log(common)
} else {
console.error('模块加载失败');
exit();
}
//--------------------------------------------------------------------------------------------------------------------------
let appConfig = common.getLocalAppConfig();
let str32 = $crypto.digest(appConfig.app_code_js_download, "MD5"); //AES对称加密key,32位字符串
let key = new $crypto.Key(str32); //这里必须用全局变量,否则会报错,提示找不到key
//--------------------------------------------------------------------------------------------------------------------------
/**
* @mainEngine 父脚本引擎对象
* @taskInfo "App.Record.GetOneTask"接口返回的任务信息对象
* @Description:监听主脚本消息
*/
events.on("prepare", function (mainEngine, taskInfo) {
// log("任务参数:" + JSON.stringify(taskInfo))
myApp.mainEngine = mainEngine;
myTaskInfo = taskInfo ? taskInfo : {};
moduleParam = taskInfo.module_param;
myCustomParam = taskInfo.custom_param;
if (moduleParam) {
// console.log('用户任务参数:' + JSON.stringify(moduleParam));
for (var item in moduleParam) {
myModuleParam[item] = moduleParam[item];
}
}
// log('任务信息',JSON.stringify(taskInfo));
// log('数据类型2:',typeof (taskInfo),typeof (myModuleParam));
try {
if (myTaskInfo.mode != '3') {
//更新用户任务
common.modifyOneTask(myTaskInfo.task_id, 2, JSON.stringify(myTaskInfo)); //更新任务(0,锁定;1,待执行;2,执行中;3,成功;4,失败;5,超时;)
}
if (myCustomParam.is_limited_time === "1" || (Number(myCustomParam.limit_time) > 0 && !myCustomParam.is_limited_time)) {
log('任务限时:' + myCustomParam.limit_time + "秒");
// 限时任务,检测任务超时
threads.start(function () {
let date1 = new Date(); //开始时间
let date2 = date1.getTime();
//在新线程执行的代码
while (true) {
let date3 = new Date(); //结束时间
let date4 = date3.getTime();
if ((date4 - date2) > Number(myCustomParam.limit_time) * 1000) {
// 设置超时:防止有的页面,比如广告页,没有明显的标识。会出现阻塞的问题。
log("任务已超时。任务ID:" + myTaskInfo.task_id);
common.modifyOneTask(myTaskInfo.task_id, 5, JSON.stringify(myTaskInfo)); //更新任务
break;
} else {
sleep(10 * 1000);
};
};
});
} else {
log('任务不限时');
};
// 判断应用是否安装
let name = getAppName(myApp.packageName);
if (name != myApp.appName) {
console.error('指定应用并未安装:' + myApp.appName);
} else {
main();
}
} catch (err) {
// log("捕获到异常--->");
log(err);
} finally {
// log("不管发生不发生错误,我都会执行--->");
};
// clearInterval(ID); //取消一个由 setInterval() 创建的循环定时任务。
});
//当脚本正常或者异常退出时会触发该事件。
//事件处理中如果有异常抛出,则立即中止exit事件的处理(即使exit事件有多个处理函数)并在控制台和日志中打印该异常
events.on("exit", function () {
threads.shutDownAll(); //停止所有线程
while (currentPackage() == myApp.packageName) {
back(); // 两次回退,快速结束APP
sleep(200);
back();
sleep(2000);
};
home();
console.hide();
try {
//向主脚本发送一个事件,该事件可以在它的events模块监听到并在脚本主线程执行事件处理。
myApp.mainEngine.emit("control", "完成");
} catch (error) { }
});
//--------------------------------------------------------------------------------------------------------------------------
// // ////////脚本运行参数示例:
// myTaskInfo = {
// "task_id": "1",
// "module_id": "1",
// "module_name": "yanghao",
// "module_group_id": "1",
// "module_param": {
// "watch_num": "3",
// "watch_min": "3",
// "watch_max": "5",
// "layuiTreeCheck_1": "1",
// "layuiTreeCheck_9B2EDAE5239A1B55": "9B2EDAE5239A1B55",
// "layuiTreeCheck_CE36CD237F859F17": "CE36CD237F859F17"
// },
// "custom_param": {
// "is_limited_time": "0",
// "limit_time": "600",
// "wait_time_min": "1",
// "wait_time_max": "3",
// "delay_min": "1",
// "delay_max": "3"
// },
// "module_url": "http://new-cloud.feiyunjs.cn/components/Module/aweme/yanghao.js",
// "mode": "1",
// "start_time": "",
// "task_source": 0,
// "state": "1",
// "imei": "9B2EDAE5239A1B55",
// "device_number": "1B55",
// "callback_data": "",
// "remarks": "",
// "add_time": "2023-04-21 20:33:42",
// "update_time": "",
// "replenish_num": 0,
// "complete_num": 0
// }
// moduleParam = myTaskInfo.module_param;
// myCustomParam = myTaskInfo.custom_param;
// if (moduleParam) {
// // console.log('用户任务参数:' + JSON.stringify(moduleParam));
// for (var item in moduleParam) {
// myModuleParam[item] = moduleParam[item];
// }
// }
// // 判断应用是否安装
// if (getAppName(myApp.packageName)) {
// main();
// } else {
// console.error('指定应用并未安装:' + myApp.appName);
// }
//--------------------------------------------------------------------------------------------------------------------------
function main() {
console.show();
//------------------------------------------------------------
// log("脚本参数:" + JSON.stringify(myModuleParam))
log(">>> 开始执行:" + myTaskInfo.module_name);
log("任务ID:" + myTaskInfo.task_id);
home();
core();
log("任务ID:" + myTaskInfo.task_id);
log(">>> 任务完成:" + myTaskInfo.module_name);
exit(); //激活退出事件
};
function core() {
let isStop = false; //完成任务后是否停止
let isFail = false //是否失败
let delay = random(Number(myCustomParam.delay_min), Number(myCustomParam.delay_max));
//--------------------------------------------------------------------------------------------------------------------------
let version = common.getPackageVersion(myApp.packageName);
log("目标App版本:" + version);
// 启动应用
launch(myApp.packageName);
sleep(10000);
common.clickNodeEx('text', '始终允许|允许', delay);
log('应用启动结果:', currentActivity());
log('需浏览作品 ' + myModuleParam.watch_num + ' 个');
while (true) {
myApp.activity = currentActivity();
// console.log("页面地址:" + myApp.activity)
if (isFail) {
common.modifyOneTask(myTaskInfo.task_id, 4, JSON.stringify(myTaskInfo), JSON.stringify(info)); //更新任务
break; //跳出循环
} else if (isStop) {
// home();
// 任务执行成功后,将任务结果回传给服务器
let data = {};
data.result = '共浏览 ' + myModuleParam.watch_num + ' 个';
console.info(data);
common.modifyOneTask(myTaskInfo.task_id, 3, JSON.stringify(myTaskInfo), JSON.stringify(data)); //更新任务
break; //跳出循环
};
// !!!这里编写脚本的核心代码
// // 简单示例:
// for (let index = 0; index < 100; index++) {
// log(index);
// sleep(500);
// // 当满足设定条件时,停止脚本执行,告诉后台任务成功/失败
// if (index > 50) {
// isStop = true; //脚本执行成功
// break;
// }
// }
// 翻页浏览作品
for (ii = 0; ii < Number(myModuleParam.watch_num); ii++) {
swipe(random(device.width / 3, device.width / 2), random(device.height * 9 / 10, device.height * 8 / 10), random(device.width / 3, device.width / 2), random(device.height * 1 / 10, device.height * 0.5 / 10), random(500, 1000));
let watchTime = random(Number(myModuleParam.watch_min), Number(myModuleParam.watch_max));
log('浏览第 ' + (ii + 1) + ' 个作品 ' + watchTime + ' 秒');
sleep(watchTime * 1000);
};
isStop = true; //脚本执行成功
};
};
```
调试运行,日志如下
```vb
22:00:39.618/V: 开始运行[[remote]yanghao.js]
22:00:39.633/D: 引用公共模块
22:00:39.706/D: >>> 开始执行:yanghao
22:00:39.713/D: 任务ID:1
22:00:39.722/D: 目标App版本:24.7.0
22:00:51.243/D: 应用启动结果: com.ss.android.ugc.aweme.main.MainActivity
22:00:51.245/D: 需浏览作品 3 个
22:00:51.782/D: 浏览第 1 个作品 4 秒
22:00:56.456/D: 浏览第 2 个作品 5 秒
22:01:01.972/D: 浏览第 3 个作品 4 秒
22:01:05.977/I: {}
22:01:06.180/D: 任务ID:1
22:01:06.183/D: >>> 任务完成:yanghao
```
# 上传脚本
脚本编写完成后,先==屏蔽测试区的代码==。
然后上传到服务器。

上传以后,进入脚本编辑页面,点击右侧的访问按钮,测试一下脚本是否已经更新。

如果没有更新,可清理一下浏览器的缓存。
如果脚本中的中文在浏览者中显示乱码,要在VS中看一下文件的编码是否为UTF8,只要是这个编码就可以。

# 脚本安全
为了防止脚本被别有用心的人获取到,你可以使用一些JavaScript加密工具,对编写好的js脚本进行加密。
需要注意的是,有的加密工具,加密后autojs是无法读取和执行的。
这一块请自行测试和解决。