翻文档的时候,我想找的是「识别到文字怎么点下去」。ocrImage 那一节写得挺全,参数、超时、返回值都有,示例代码最后一行打印了四个数。
logd("文字 " + value.label + " confidence " + value.confidence
+ " range " + value.x + "," + value.y + ","
+ (value.width + value.x) + "," + (value.height + value.y));
x、y、x 加 width、y 加 height。四个数画出一个矩形,左上角和右下角。文档到这儿就结束了,没提后面该点哪儿。
第一次看这段示例,我默认 x、y 就是能点的点,拿到就往 clickPoint 里塞。错了,落点在文字框左上角那个顶点上。按钮要是圆角的,这一下就空了;文本越长越明显,height 越大,左上角离中心越远。
脚本识别文字然后点击这件事,难的就是中间这一步。识别准了、坐标拿到了,点不中还是白搭。这也是大多数人写文字识别脚本时卡住的地方;前面识别、后面点击,两个都能单独跑通,接起来就不对。
文档给的矩形怎么变成能点的点
中心很好算,x 加半个宽,y 加半个高。难的是知道要这么算,因为文档里没有这一步。
有人问脚本点击坐标怎么设置。要设的其实只有屏幕尺寸那一次,剩下的偏移都是算出来的。
let cx = v.x + Math.floor(v.width / 2);
let cy = v.y + Math.floor(v.height / 2);
拿「确认」按钮举例,x 是 320、y 是 1180、宽 120、高 48。算出来 380 和 1204,这个点落在按钮正中。
矩形画出来的是文字占的位置,能点的中心要自己算。这两件事在 OCR 里被合成一个返回值,所以容易混。找图的返回结构不一样,那边给的是 left、right、top、bottom,左右取中、上下取中;算法完全不同。两个模块的文档分在两个文件里,同时看到的人不多。
一次识别通常返回好几条。页面上的标题、按钮、提示语全在里面。得靠 label 匹配再加上 confidence 过滤才挑得出来。
一段能抄的写法
function clickText(tocr, target, retry = 3) {
for (let i = 0; i < retry; i++) {
let img = image.captureFullScreenNoAuto();
if (img == null) {
sleep(500);
continue;
}
let res = tocr.ocrImage(img, 10 * 1000, {"matMode": 1});
image.recycle(img);
if (res && res.length > 0) {
let hit = res.find(v =>
v.label.indexOf(target) >= 0 && v.confidence >= 0.8
);
if (hit) {
usbHidEvent.clickPoint(
hit.x + Math.floor(hit.width / 2),
hit.y + Math.floor(hit.height / 2)
);
return true;
}
}
sleep(800);
}
return false;
}
image.recycle(img) 千万别漏。截图对象不回收,占的是手机内存;跑一批 30 台设备、每台几十轮,涨得挺快。
超时给了 10 秒。第二个参数就是毫秒,跑满才返回空。文档示例里写的是 30 秒,照抄下来,界面明明没出来也要干等半分钟。
置信度卡在 0.8。太低会把「确认」认成「确以」,点了没用;太高可能一个都匹配不上。七成到八成五之间比较稳,界面文字清楚就往高取。我试过 0.95,连确认按钮都匹配不出来,又退回 0.85。
截图要用 captureFullScreenNoAuto,别用 captureFullScreen。前者不需要开自动化,配合 USB HID 全程不用装 App。这条路径从 EC iOS USB 10.7.0 起提供,手机要 iOS 17 及以上;代价是慢一点,文档里也写了。
两个函数名太像,改脚本时容易顺手写错一个。写错了不报错,只是慢,或者截图失败。
调用的时候前面还得开会话和初始化。
function main() {
let r = usbHidEvent.sessionStart(true);
if (r != null && r != "") { logw("会话失败 " + r); return; }
usbHidEvent.setScreenSize(1170, 2532);
ocr.releaseAll();
let tocr = ocr.newOcr();
if (!tocr.initOcr({"type": "appleVision", "level": "accurate",
"languages": "zh-Hans"})) {
loge("初始化失败 " + tocr.getErrorMsg());
return;
}
if (clickText(tocr, "确认")) {
sleep(1500);
}
}
releaseAll 要放在 newOcr 前面。上一次没释放干净的实例会占着内存,一个脚本里反复调用时特别明显。
点不动的时候,先从识别结果里找原因
日志里能看到 confidence,先看这个数。
列表页有好几个「查看」,find 只拿第一个,往往是最上面那个,不是你要的。两个办法,截图前把区域裁到目标附近,用 image.clip 缩小范围;或者按 y 坐标排一下序再取第几个。
识别到了但点不动,多半是置信度太低。七成以下的结果,label 本身就是错的,点下去当然没反应。
还有一种,OCR 返回空,但截图是好的。界面刚切过去,动画还没结束,截到的图是模糊的;加个 sleep 等动画走完,比提高重试次数管用。
这三种都是「识别到了,但用不上」。市面上的文字识别点击器大多识别一下就点,不判断。要做成识别文字自动点击,判断条件得比识别本身更严;写自动点击脚本就得自己扛这一层。
常见问题
x、y 能直接点吗?
不能。那是文字框左上角,要加半个宽高才是中心。
多个同名结果怎么选?
裁剪截图缩小范围,或按 y 排序后取指定序号。find 永远只返回第一个匹配。
OCR 每次都要初始化?
不用。脚本开头一次就够。不过正式任务里 OCR 较多时,任务结束后引擎会释放,下次同类任务第一步可能多等几秒。
不开自动化能用吗?
能。captureFullScreenNoAuto 不需要自动化环境。配合 USB HID 点击,全程不装代理 IPA。
iEasyClick 是手机自动化 AI 智能体平台,覆盖安卓免 root、iOS 免越狱(代理/蓝牙 HID/OTG HID)、鸿蒙 Next 三大生态,提供脚本开发、苹果群控、本地中控投屏与云控系统。→ 了解全部产品
想要真实跑起来?
本文介绍的方案均可基于 EasyClick 能力在 iEasyClick 落地。官网提供完整文档、开发工具与自动化产品,免费体验。