用AI开发手机点赞工具的实战经验

2025年7月11日,距离今天2026年4月2日,只有短短9个月而已,但是对于突飞猛进的AI而言,可能已经是相当长的时间了。在这里记录一下那一天9个月前,我用豆包AI帮助(主导)做的手机上的两个点赞工具,以及近期的一个小工具。

因为工具较小,我几乎没有编程。我在手机上与豆包沟通,在手机上复制粘贴代码到工具,全程没有用PC,没用键盘没改代码。

积累到的经验包括,1.可以与AI讨论技术方案,其实有的时候它的代码很差,技术就可以相当不错,这两件事情是对立的;2.人类描述故障现象,以及猜测使用什么样的技术方案更合理,尤其是当AI看不到现象时,这两点都很有帮助;3.人类需要部署代码、运行,以及观察和描述现象。

1. keep点赞工具

Keep是一个运动软件,里面的社交功能,可以看到其他人锻炼消息。我习惯于为每一条消息点赞,用鼓励为同道中人提供些情绪价值。不过有的时候,有的人真的是太能练了,运动的记录哗哗刷屏。我点起赞来也有些疲惫,所以想到做自动化工具吧。

(1)先讨论技术方案。

豆包的答复表明,对技术方案讨论是必要的,我的思路太狭隘了。我以为她会selenium之类的,她给出了3种PC端控制方案,3种安卓的方案,还有混合方案。其中,她推荐的方案是纯安卓的方案中 autox.js,我听HYR同学提到过,就选了这个方案。

(2)请教工具使用

(3)降低颗粒度,提高确定性

A. 一蹴而就 是幻想

当时的实践表明,这么复杂的功能,一次性沟通是个失策。换句话说,如果你作为人类读了上面这一段一段文字,感觉累的话,那么AI也不行,至少当时的情况是这样的。当她信誓旦旦反复说这一次肯定就可以逆行了的时候,你还会有情绪反应。

当你对于使用的工具不熟悉时,也会有挫败感。AI通常会假设你对工具充分熟悉,不过好在,当你发问的时候,她并不会嘲笑你。

这样折腾了不少的轮次,我就不一一列举了,请想象一下我挫败的感觉。

后来终于找到了绿色喇叭。

B. 在结对编程中的任务分工,某部分 谁能力强就谁做

到这时,我已经了解到AI的设计和模式识别非常一般,这种事儿,人手操作容易得多。

C.降低颗粒度

AI倾向于他认为规模不大的时候,一次性生成所有代码。但是实践表明,她对于运行环境的错误猜测可能给调试带来很多麻烦,所以每次测试的单一的一件事情,更容易一些。

就这样,我把功能需求当中的每一个技术要点分别要求AI开发出来。我测试有效算完成,完成一个,再要求写下一个。

D. 现实一些,削减需求

有的功能并不太重要,但是实现很麻烦,很可能不是因为AI的能力不行,而是因为手机环境导致获取信息的方法受限。

所以后来有的功能就放弃了,比如跳过我自己,干脆连自己一起赞了。这是削减需求。

再例如,超过24小时以上不点赞这个功能后来也取消了,由我手动停止脚本。自己使用的工具,不提供给其他用户使用,才具有这样的便利。事实上,多数产品当中的多数代码都是设置环境、限制用户操作,以及防呆。并没有多少积分难度,但是工作量不小。

由autox.JS自动运行keep再切换到特定的tab,这个功能也放弃了,由我手动操作到达这个位置再开始运行脚本好了。

E. 情绪感受、编程环境,以及“看到了才知道这不是我要的”

有的调试体验还是不错的。

例如,我搞混了 向上 和 向下 滑动,纠正的时候,AI并没有嘲笑我,说“连这个都分不清吗?”

为了调试方便,我禁止AI要求我增量修改代码,她遵从了,虽然需要反复重申很多次。事实上,即使我的环境是否粘贴代码,我也觉得AI对于描述如何修改的表述能力欠佳,精确程度不足,指代不明经常出现,可能她学习的语料库就是这样的。

有的地方,人类也没有想到界面(需求)会是这样,现象出现了才意识到还有这些情况。

F.集成

当所有技术类型都完成,并删除实现困难的需求以后,把所有代码集成在一起。

视频

Keep点赞工具 - 杨贵福的视频 - 知乎

https://www.zhihu.com/zvideo/1927419261376267022

代码在本文最后。

2. 微信读书点赞

因为有了上一个点赞工具的合作开发经验,所以这次我跳过了对绿喇叭、红心之类可见目标的描述,一开始就用布局分析工具找到了空间的ID。

接下来几轮,修改AI的代码风格,这样我就不必手动修改了。

接着,再次重申要求。

有对技术细节的讨论,包括我逐步才意识到的代码需要识别和应对的环境特征。

屏幕我每次上滑半页,所以显示的范围有所重复。如果完全避免重复,我担心需要精确定位,或者有遗漏。为了避免重复中文网友被我连续点赞两次导致点赞被清除,下面这个功能是识别是否点过赞,点过的话,不要再点一次。

事实上,这么简单的“复杂”情情情况只出现了一次。接着我的要求增加了新的功能,也就是最后一个功能。

运行时,我用肉眼跟踪,如果点赞到了本周完全没有阅读的网友,我就手动停止脚本。微信读书的启动和调整到特定页面也是由我手动操作的。这些需求的削减依据在第一个项目中积累的经验。相比之下,上一个小项目,主要时间花费在(1)实现困难而意义不大的需求,最后可能还是放弃了,(2)要求AI做她不擅长的事情,后来难以触达的真实环境,例如识别某个控件的ID,(3)颗粒度过大。

所以,没有几轮讨论,开发就完成了。

微信读书点赞 - 杨贵福的视频 - 知乎

https://www.zhihu.com/zvideo/1927736304004735247

代码在本文最后。

3. 微信读书左划

需要这个脚本的原因是,微信读书每隔一段时间内发放一批免费的书,可以领2本,要求每一本阅读5分钟。看到消息的时候,我可能刚好没有时间读10分钟,又担心过来事儿,把这事忘了,错过了占便宜。

所以我让豆包写一段脚本。

之所以滑动的间隔和持续的时间定这么短,是为了能得到尽快响应,调试方便。代码一次性跑的很好,因为避免了前述提到的问题 困难而意义不大的需求、在无法真正触达的情况下与真实环境的交互、过大的颗粒度。

这增加的一个需求是我事先没有想到的。

脚本刚一完成,我就意识到它并无必要,因为微信读书支持朗读的功能,你让它读一分钟就算数。不过,我也没有什么可遗憾的,因为写这个脚本也就是两三分钟的时间,在豆包的帮助下。

代码在本文最后。

这一段我也不附视频了,文字描述一下,就是每半分钟左滑一次,持续6分钟。我还考虑到,如果遇到识别机器人的机制,可以在每次左滑中加一个随机的时间间隔。没有用到。

4. 复杂任务,不行

我最近尝试过用豆包开发一脚的autox.js朗读电子书,她信誓旦旦地说,容易实现。并不。稍微复杂一些的功能,她既没有能力实现(当然,也可能由于合作者我的无能),也没有自知之明。也许性格设定上,她就是那种大喊“没问题!”的昭和男儿吧。

简单的经验是,如果你感觉对话的轮数较多,而仍未实现,那么无论希望多么迫近和逼真,非常可能,那就是不能实现。别相信她。

另,语音朗读电子书,@voice aloud reader 非常好。

代码 微信读书点赞

"nodejs";

// 自动点赞并上滑脚本

function main() {

// 请求无障碍服务权限

auto.waitFor();

// 定义循环次数

const TOTAL_CYCLES = 10;

for (let cycle = 1; cycle <= TOTAL_CYCLES; cycle++) {

log(`=== 开始第 ${cycle}/${TOTAL_CYCLES} 轮点赞 ===`);

// 设置查找元素超时时间

sleep(1000);

// 查找所有点赞容器

let containers = id("friends_rank_praise_container").find();

if (containers.empty()) {

log("未找到点赞容器,可能已到达页面底部");

break; // 跳出循环

}

log(`本轮找到 ${containers.size()} 个点赞容器`);

// 遍历容器并处理

for (let i = 0; i < containers.size(); i++) {

let container = containers.get(i);

let icon = container.findOne(id("friends_rank_praise_icon"));

if (icon) {

let isSelected = icon.selected();

log(`容器 ${i+1} 内的图标选中状态: ${isSelected}`);

// 如果未选中,则点击容器

if (!isSelected) {

container.click();

log(`已点击容器 ${i+1}`);

// 点击后适当延迟,避免操作过快

sleep(500);

}

} else {

log(`容器 ${i+1} 内未找到点赞图标,跳过`);

}

}

log(`=== 第 ${cycle}/${TOTAL_CYCLES} 轮点赞完成,准备上滑 ===`);

// 执行上滑操作

swipe(device.width / 2, device.height * 0.8, device.width / 2, device.height * 0.2, 300);

log("已执行上滑操作");

// 上滑后等待页面加载

sleep(1500);

}

log("==== 全部点赞任务完成 ====");

}

// 执行主函数

main();

代码 keep点赞

"nodejs";

auto.waitFor();

// 定义判断是否已点击的函数

function hasClicked(horn) {

return horn.selected();

}

// 定义点赞第一个绿色小喇叭的函数

function clickFirstHorn() {

let horn = id("layoutContent").findOne();

if (horn && !hasClicked(horn)) {

horn.click();

sleep(500); // 点击间隔,避免过快

log(`已点赞第一个绿色小喇叭`);

}

}

// 定义向上滑动半屏的函数

function swipeUp() {

const width = device.width;

const height = device.height;

const startX = width / 2;

const startY = height * 0.8; // 起点:屏幕下部80%位置

const endY = height * 0.3; // 终点:屏幕上部30%位置(上滑半屏)

const swipeDuration = 500; // 滑动持续时间(毫秒)

const intervalBetweenSwipes = 800; // 每次滑动间隔时间(毫秒)

swipe(startX, startY, startX, endY, swipeDuration);

sleep(intervalBetweenSwipes);

}

// 主循环,假设执行10次滑动和点赞操作

const loopCount = 100;

for (let i = 0; i < loopCount; i++) {

clickFirstHorn();

swipeUp();

log(`完成第 ${i + 1} 次滑动和点赞操作`);

}

toast("点赞和滑动操作完成");

代码 微信读书左划

// 设置时间参数(单位:毫秒)

var interval = 1000*60; // 每次滑动间隔(1分钟)

var duration = 1000*60*7; // 总持续时间(7分钟)

// 记录开始时间

var startTime = new Date().getTime();

// 定义滑动函数

function swipeLeft() {

var width = device.width;

var height = device.height;

swipe(width * 0.8, height / 2, width * 0.2, height / 2, 300);

console.log("已向左滑动一次");

}

// 循环执行滑动

while (true) {

swipeLeft();

sleep(interval);

// 判断是否达到总持续时间

if (new Date().getTime() - startTime >= duration) {

console.log("已达到指定持续时间,脚本结束");

// 弹出任务完成提示

alert("任务完成", "已按设定完成所有滑动操作");

break;

}

}

Leave a Reply

Your email address will not be published. Required fields are marked *