18 KiB
一、思维导图
二、整体架构
通过这个脚本,我们可以实现小红书的自动打开、进入随机直播间、自动滑屏切换、点赞、关注、评论以及发布帖子等功能。该脚本尤其适合那些需要频繁进行直播互动操作的人群,接下来,我们将逐步分析这段代码中的关键实现部分。
1. 初始化及权限检查
首先,我们的代码会检查应用的悬浮窗权限。如果没有权限,则会通过悬浮窗提示用户授权,并立即退出脚本,以确保之后的界面显示功能能够正常工作。
if (!floaty.checkPermission()) {
toast("请授予悬浮窗权限");
floaty.requestPermission();
exit();
}
floaty.checkPermission()
用于检查悬浮窗权限;如果没有授权,则floaty.requestPermission()
会请求权限,并提示用户。
2. 创建悬浮窗组件
接下来,我们通过 floaty.window
创建一个包含按钮、滑动条、复选框和输入框的悬浮窗界面,以期为用户提供丰富的控制选项,这些控件允许用户开启与关闭点赞、设置点赞速度、切换评论模式、开启与关闭评论、开启与关闭自动滑屏与自动关注以及输入帖子内容等,我们使用XML 结构定义界面布局,这样可以使得用户看到的界面整洁,且功能齐全。
let window = floaty.window(
<vertical padding="8">
<button id="toggle" text="爱猫的悬浮窗" />
<!-- 包含控制按钮的组件 -->
</vertical>
);
3. 悬浮窗拖动与收起功能
为增强用户体验,我们的脚本实现了悬浮窗的拖动和展开/收起功能,以便在不需要的时候收起,免得占用太多屏幕控件。window.toggle.setOnTouchListener
方法实现了拖动逻辑,通过判断按下时间来识别用户是拖动还是点击操作。
window.toggle.setOnTouchListener(function(view, event) {
switch (event.getAction()) {
case event.ACTION_DOWN:
x = event.getRawX();
y = event.getRawY();
windowX = window.getX();
windowY = window.getY();
downTime = new Date().getTime();
return true;
case event.ACTION_MOVE:
window.setPosition(windowX + (event.getRawX() - x), windowY + (event.getRawY() - y));
return true;
case event.ACTION_UP:
if (new Date().getTime() - downTime < 200) {
window.toggle.performClick();
}
return true;
}
return true;
});
通过这种方式,用户可以自由拖动悬浮窗位置,并通过点击展开或收起控制面板以节省屏幕空间。
4. 自动点赞功能
点赞是直播互动中的关键操作,我们的脚本通过 window.likeButton.click
事件监听来实现点赞的开关控制,用户可以点击按钮来启动或停止点赞,并通过滑动条来调节点赞速度。
function startLiking() {
stopLiking(); // 先停止之前的点赞定时器,防止重复
toast("开始点赞");
likingInterval = setInterval(() => {
likePost();
}, likeSpeed);
}
点赞是通过 click()
来模拟点击屏幕右侧的指定位置实现的,其频率由 likeSpeed
控制,window.speedControl.setOnSeekBarChangeListener
用于监听滑动条变动,以实时调整点赞速度。
5. 评论功能:静态与动态评论
评论功能允许用户选择发送静态或者动态评论,静态评论是从我们预先设置的 staticComments
数组中随机抽取的,而动态评论则允许用户自定义输入内容(之后会重复发送用户的自定义内容), getStaticComment()
函数负责从预设数组中随机选择评论。
function getStaticComment() {
return staticComments[Math.floor(Math.random() * staticComments.length)];
}
评论功能的逻辑由 startLiveOrComment
函数实现。该函数根据用户选择的模式(静态/动态)来生成评论,并自动输入到评论框中。
6. 自动关注和自动滑屏
我们的脚本中提供了自动关注主播和自动滑屏切换直播间的功能,开启这两个功能后,脚本会自动检测并点击屏幕中的“关注”按钮(通过查找id和关键字同时实现,如果找不到id就找关键字),同时通过模拟滑动操作,实现了在观看一定时间后(自定义的)自动切换下一个直播的功能。
// 自动关注按钮
window.follow.click(() => {
if (!isAutoFollowing) {
autoFollowThread = threads.start(() => {
while (isAutoFollowing) {
let followButton = id("fv").findOne(2000);
if (followButton) followButton.click();
sleep(1000);
}
});
}
});
swipe(device.width / 3, device.Height / 2, device.width / 2, device.Height / 4, 100);
模拟向上滑动的功能,切换视频内容。
7. 自动发帖功能
最后,我们脚本提供了一个简易的发帖功能。用户可以发布图文或纯文字帖子,通过 createPost(content, isImagePost)
函数来实现发帖操作,函数可以模拟一系列点击操作,输入用户指定的内容,并选择添加图片或是不添加图片(根据选择的模式)并发布帖子。
function createPost(content, isImagePost) {
click(539.5, 2338); // 定位并点击发帖按钮
if (isImagePost) {
click(307, 395); // 选择图片区域
setText(content); // 输入帖子内容
click(964.5, 173.5); // 点击发布
}
}
isImagePost
参数决定是图文发布还是文字发布。这种模拟操作实现了简单的发帖功能,便于自动化管理发布内容。
三、完整代码解释
const staticComments = [ /* 静态评论内容数组,用于随机选择评论内容 */ ];
const deviceW = 1080; // 设备宽度(可用device.width代替,但该函数有时会出现返回值为0的情况)
const deviceH = 2400; // 设备高度(可用device.height代替,但该函数有时会出现返回值为0的情况)
let isLiking = false; // 控制点赞开关
let iscomment = false; // 控制评论开关
let likeSpeed = 1000; // 初始点赞速度(毫秒)
let likingInterval; // 存储点赞的定时器
// 检查悬浮窗权限,如果没有则请求权限并退出脚本
if (!floaty.checkPermission()) {
toast("请授予悬浮窗权限");
floaty.requestPermission();
exit();
}
// 创建悬浮窗
let window = floaty.window(
<vertical padding="8">
<button id="toggle" text="爱猫的悬浮窗" />
<vertical id="controls" visibility="gone">
<button id="openButton" text="打开直播" />
<button id="likeButton" text="开始点赞" />
<text text="速度" textColor="#ffffff" />
<seekbar id="speedControl" max="2000" progress="500" layout_weight="1" />
<checkbox id="enableComment" text="是否发送评论" textColor="#ffffff"/>
<checkbox id="enableStaticComment" text="使用静态评论" textColor="#ffffff"/>
<input id="liveCommentInput" hint="在这里输入动态评论内容" />
<button id="startLiveButton" text="发评论" />
<button id="follow" text="关注" w="*"/>
<button id="autoRefresh" text="自动刷" w="*"/>
<button id="stopButton" text="停止运行" />
<input id="postContentInput" hint="请输入发帖内容" />
<checkbox id="isImagePost" text="图文发布" textColor="#ffffff"/>
<button id="publishPostButton" text="发布帖子" />
</vertical>
</vertical>
);
setTimeout(() => {
ui.run(() => {
window.liveCommentInput.setHintTextColor(colors.parseColor("#ffffff")); // 设置提示文字颜色为白色
window.postContentInput.setHintTextColor(colors.parseColor("#ffffff"));
});
}, 500); // 延迟 500 毫秒
// 设置初始位置和拖动
window.setPosition(100, 100);
window.setSize(-2, -2);
// 监听触摸事件以实现拖动功能
window.toggle.setOnTouchListener(function(view, event) {
switch (event.getAction()) {
case event.ACTION_DOWN:
x = event.getRawX();
y = event.getRawY();
windowX = window.getX();
windowY = window.getY();
downTime = new Date().getTime();
return true;
case event.ACTION_MOVE:
window.setPosition(windowX + (event.getRawX() - x), windowY + (event.getRawY() - y));
return true;
case event.ACTION_UP:
if (new Date().getTime() - downTime < 200) {
window.toggle.performClick();
}
return true;
}
return true;
});
// 切换悬浮窗的展开和收起状态
window.toggle.click(function() {
if (window.controls.visibility === 0) {
window.controls.visibility = 8; // 收回
window.toggle.setText("展开");
} else {
window.controls.visibility = 0; // 展开
window.toggle.setText("爱猫的悬浮窗");
}
});
// 打开直播按钮事件
window.openButton.click(() => {
toast("开始运行");
threads.start(function() {
startLiveOrSignIn(); // 在新线程中调用,避免阻塞 UI 线程
});
});
// 停止按钮事件
window.stopButton.click(() => {
toast("停止运行");
window.close(); // 关闭悬浮窗
exit(); // 停止脚本运行
});
// 点赞按钮的点击事件
window.likeButton.click(() => {
isLiking = !isLiking; // 切换点赞状态
if (isLiking) {
window.likeButton.setText("停止点赞");
startLiking(); // 开始点赞
} else {
window.likeButton.setText("开始点赞");
stopLiking(); // 停止点赞
}
});
// 发布帖子按钮事件
window.publishPostButton.click(() => {
let postContent = window.postContentInput.text(); // 获取帖子内容
let isImagePost = window.isImagePost.isChecked(); // 获取是否图文发布
if (postContent) {
threads.start(() => {
createPost(postContent, isImagePost); // 调用发帖函数
});
toast("正在发布帖子...");
} else {
toast("请输入发帖内容!");
}
});
// 滑动条控制点赞速度
window.speedControl.setOnSeekBarChangeListener({
onProgressChanged: function(seekBar, progress, fromUser) {
likeSpeed = 2500 - progress; // 调整点赞速度
toast("当前速度: " + likeSpeed + " 毫秒");
if (isLiking) {
stopLiking();
startLiking();
}
}
});
// 点赞功能
function startLiking() {
stopLiking(); // 确保之前的定时器被清除,避免重复
toast("开始点赞");
likingInterval = setInterval(() => {
likePost();
}, likeSpeed);
}
// 停止点赞功能
function stopLiking() {
toast("停止点赞");
if (typeof likingInterval !== 'undefined') {
clearInterval(likingInterval); // 清除定时器
likingInterval = undefined; // 重置 likingInterval
}
}
// 点赞操作
function likePost() {
console.log("执行点赞操作");
click(900, 1000);
sleep(50);
click(900, 1000);
sleep(50);
}
// 保持脚本运行
setInterval(() => {}, 1000);
// 打开直播功能
function startLiveOrSignIn() {
launchApp('小红书');
sleep(6000);
swipe(1080 / 2, 2400 / 4, 1080 / 2, 2400 * 3 / 4, 500);
sleep(1000);
click(273.5, 682);
sleep(5000);
}
// 自动直播或评论
function startLiveOrComment(enableComment, enableStaticComment, dynamicCommentText) {
while (true) {
if (enableComment && !iscomment) {
let commentBox = desc("评论输入框").clickable(true).findOne(5000);
if (commentBox) {
commentBox.click();
sleep(1000);
enableStaticComment = window.enableStaticComment.checked;
dynamicCommentText = getDynamicCommentText();
let commentText = enableStaticComment ? getStaticComment() : dynamicCommentText;
input(commentText);
sleep(500);
let sendButton = text("发送").findOne(3000);
if (sendButton) {
sendButton.click();
console.log("评论发送成功:" + commentText);
} else {
console.log("未找到发送按钮");
}
sleep(3000);
} else {
console.log("未找到评论框,无法发送评论");
}
}
}
}
// 获取静态评论
function getStaticComment() {
return staticComments[Math.floor(Math.random() * staticComments.length)];
}
// 开始评论按钮事件
window.startLiveButton.click(() => {
iscomment = !iscomment;
if (iscomment) {
window.startLiveButton.setText("开始评论");
} else {
window.startLiveButton.setText("停止评论");
}
let commentEnabled = window.enableComment.checked;
let useStaticComment = window.enableStaticComment.checked;
let liveCommentText = window.liveCommentInput.text();
threads.start(() => {
startLiveOrComment(commentEnabled, useStaticComment, liveCommentText);
});
if (commentEnabled && (useStaticComment || liveCommentText)) {
toast("开始看直播并发送评论");
} else {
toast("开始看直播,不发送评论");
}
});
// 动态评论输入
window.liveCommentInput.click(() => {
dialogs.rawInput("输入动态评论内容").then(input => {
if (input) {
window.liveCommentInput.setText(input);
}
});
});
// 获取动态评论内容
function getDynamicCommentText() {
return window.liveCommentInput.getText();
}
// 自动刷新和关注功能
let isAutoRefreshing = false;
let isAutoFollowing = false;
let autoRefreshThread;
let autoFollowThread;
// 自动关注按钮事件
window.follow.click(() => {
if (!isAutoFollowing) {
isAutoFollowing = true;
autoFollowThread = threads.start(() => {
while (isAutoFollowing) {
let followButton = id("fv").findOne(2000);
if (followButton) {
followButton.click(); // 点击关注按钮
console.log("已点击关注(通过ID)");
} else {
// 如果通过 ID 找不到按钮,尝试通过文本查找
followButton = text("关注").findOne(2000);
if (followButton) {
followButton.click(); // 点击关注按钮
console.log("已点击关注 (通过文本)");
} else {
console.log("未找到关注按钮 (通过ID和文本)");
}
}
sleep(1000); // 等待 1 秒再进行下一次操作
}
});
// 更新按钮文本
window.follow.setText("停止关注");
} else {
// 如果已经在自动关注状态,则停止自动关注
console.log("停止自动关注");
isAutoFollowing = false;
if (autoFollowThread) {
autoFollowThread.interrupt(); // 停止线程
}
// 恢复按钮文本
window.follow.setText("关注");
}
});
// 自动刷按钮事件
window.autoRefresh.click(() => {
if (!isAutoRefreshing) {
isAutoRefreshing = true;
console.log("开始自动刷");
// 创建一个新线程进行自动刷操作
autoRefreshThread = threads.start(function() {
while (isAutoRefreshing) {
swipe(deviceW / 3, deviceH / 2, deviceW / 2, deviceH / 4, 100); // 模拟向上滑动
console.log("切换到下一个视频");
sleep(5000); // 等待 5 秒再执行下一个滑动
}
});
// 更新按钮文本
window.autoRefresh.setText("停止自动刷");
} else {
// 如果已经在自动刷状态,则停止自动刷
isAutoRefreshing = false;
if (autoRefreshThread) {
autoRefreshThread.interrupt(); // 停止线程
}
console.log("停止自动刷");
window.autoRefresh.setText("自动刷"); // 恢复按钮文本
}
});
// 发帖功能实现
function createPost(content, isImagePost) {
click(539.5, 2338); // 点击发帖按钮位置
sleep(3000);
if (isImagePost) {
console.log("图文发帖");
click(307, 395); // 选择图片区域
let nextBox = desc("下一步").clickable(true).findOne(3000);
if (nextBox) {
nextBox.click();
}
sleep(1500);
click(926, 2323); // 点击继续按钮
sleep(2000);
click(540, 796); // 选择图片的描述框
sleep(1000);
setText(content); // 输入内容
sleep(1000);
click(964.5, 173.5); // 发布帖子
sleep(1000);
} else {
console.log("仅文字发帖");
click(341, 2336.5); // 选择文字发帖区域
sleep(1500);
click(374, 1088); // 点击输入框
sleep(1500);
setText(content); // 输入内容
sleep(1000);
let nextBox = desc("下一步").clickable(true).findOne(3000);
if (nextBox) {
nextBox.click();
}
sleep(9000);
nextBox = desc("下一步").clickable(true).findOne(3000);
nextBox.click();
sleep(2000);
click(675, 2271); // 发布帖子
}
console.log("发帖完成");
}
// 监听发帖内容输入点击事件
window.postContentInput.click(() => {
dialogs.rawInput("请输入发帖内容").then(input => {
if (input) {
window.postContentInput.setText(input); // 显示输入内容
}
});
});