EasyClick 苹果群控 USB HID 不安装 APP 如何截图?
不装 App 也能截图,用 image.captureFullScreenNoAuto(),iOS 17 以上先调一次 image.resetCaptureScreenNoAutoEnv()。
代码例子:
截完的图可以直接交给 OCR:找出「搜索」两个字的位置,点进去,再往下滑视频。从截图、识别、点击到滑动,都在这一段里:
let tocr = null;
function initOcr() { ocr.releaseAll(); tocr = ocr.newOcr(); return tocr.initOcr({ "type": "paddleOcrOnnxV6", "numThread": 2, "single": 0, "matMode": 1, "padding": 32, "maxSideLen": 640, "doAngleFlag": 0, "mostAngleFlag": 0 });}
function findText(img, keyword) { let result = tocr.ocrImage(img, 30 * 1000, {"padding": 32, "numThread": 1}); if (!result) return null; for (let i = 0; i < result.length; i++) { let item = result[i]; if (item.label && item.label.indexOf(keyword) >= 0) { return { x: parseInt(item.x + item.width / 2), y: parseInt(item.y + item.height / 2) }; } } return null;}
function main() { usbHidEvent.sessionStart(); usbHidEvent.setScreenSize(1170, 2532); // 换成你的机型分辨率
image.resetCaptureScreenNoAutoEnv(); sleep(1000); image.useOpencvMat(1); initOcr();
let img = image.captureFullScreenNoAuto(); if (img == null) { loge("截图失败"); return; }
let pos = findText(img, "搜索"); image.recycle(img);
if (pos) { usbHidEvent.clickPoint(pos.x, pos.y); logd("点了搜索 " + pos.x + "," + pos.y); sleep(1500); } else { loge("没识别到「搜索」"); }
// 往下滑,看下一个视频 for (let i = 0; i < 5; i++) { usbHidEvent.swipeToPoint(585, 2000, 585, 600, 600); sleep(2000); }
usbHidEvent.sessionStop(); tocr.releaseAll();}
main();USB HID 不装 App 也能截图:captureFullScreenNoAuto 截完交给 OCR 识别文字,点识别结果,再滑视频页。
这段代码在做什么
usbHidEvent.sessionStart() 开 HID 会话,setScreenSize 设屏幕尺寸。点击和滑动的坐标都以这个尺寸为基准,设错了就会点偏。
image.resetCaptureScreenNoAutoEnv() 是 iOS 17 以上必须做的,先启动截图隧道;低版本调用不报错但无效。调完等一秒再截。
image.useOpencvMat(1) 把图片切到 mat 存储,截图、OCR 都吃这个格式,内存更省。
image.captureFullScreenNoAuto() 截一张无自动化图。截不到返回 null,先别急着写业务。
OCR 初始化用 paddleOcrOnnxV6,配一组偏快的参数:maxSideLen: 640、doAngleFlag: 0、mostAngleFlag: 0。日常正立的界面够用,遇到小字再调回 960。
tocr.ocrImage(img, 30 * 1000, {...}) 返回一个数组,每条带 label、confidence、x、y、width、height。要点的位置取文字框中心:
x = item.x + item.width / 2;y = item.y + item.height / 2;找到含「搜索」的文章坐标,用 usbHidEvent.clickPoint(x, y) 点过去。clickPoint 返回 null 或空字符串算成功,返回别的字符串是错误信息。
滑视频用 usbHidEvent.swipeToPoint(585, 2000, 585, 600, 600):起点在屏幕下方,终点在上方,从下往上滑,等于翻到下一个。每次滑完等两秒,让视频加载。
最后 sessionStop 关会话,tocr.releaseAll() 释放 OCR 资源,image.recycle(img) 回收截图对象。
USBHID 场景为什么用 NoAuto 截图
USB HID 和代理自动化是两条路,同一台设备只能开一条。USBHID 的特点是手机上不装 App、不装描述文件,那就不能用需要自动化服务的截图函数。
几种截图方式的区别:
| 方式 | 依赖 | 速度 | 适合 |
|---|---|---|---|
captureFullScreenNoAuto | 不开自动化;iOS 17+ 先重置隧道 | 稍慢 | USBHID、BLE,没装代理 IPA |
captureFullScreen / captureFullScreenEx | 自动化服务(代理或镜像) | 快 | 常规代理模式 |
imageAgent.captureFullScreenEx | 手机内执行 | 省传输 | 代理模式、要在手机侧处理 |
截图之后:使用OCR 找文字,再去滑视频
真拿它刷短视频,跑一天下来是这么个循环:
- 截一张图
- OCR 识别,按关键字找目标,比如「搜索」「关注」「私信」
- 算中心点,
clickPoint点过去 swipeToPoint往上滑,进下一个视频- 等加载,再截一张图,重复
容易错误的是这几处:
- 关键字用
indexOf做包含匹配。「搜索」和「搜索框」「搜索商品」都能匹配上 - 滑动的起点终点别贴着屏幕边缘,留一百多像素。贴边滑容易触发系统手势,滑到一半弹回去
- 每次循环都重新截图。用上一轮的图算这一轮的坐标,界面变了,点过去就是别的按钮
- OCR 一次要几百毫秒,循环里别太密集,需要sleep,滑完等两秒比连续滑被风控强
如果识别不到,先用 image.saveTo(img, "debug.png") 把图存下来看一眼,查看图片是否正确。
耗时太大或者黑屏了如何排查
耗时别猜,拿 console.time 量十次:
for (let i = 0; i < 10; i++) { console.time("shot"); let img = image.captureFullScreenNoAuto(); logd("第 " + (i + 1) + " 次: " + console.timeEnd("shot") + " ms"); if (img != null) image.recycle(img); sleep(300);}影响耗时的地方,从大到小:分辨率、图片格式(PNG 大、JPG 小)、有没有开预截图、有没有切 mat。
返回 null:先确认设备亮屏、没锁屏,iOS 17 以上调过 resetCaptureScreenNoAutoEnv。隧道没起来的时候日志里全是 null,人容易去翻点击函数,其实跟点击没关系。连续 null 就重置环境,等十秒恢复再重试:
let img = image.captureFullScreenNoAuto();if (img == null) { image.resetCaptureScreenNoAutoEnv(); sleep(10000); img = image.captureFullScreenNoAuto();}截出来是黑图:设备锁屏、目标 App 在后台、隧道刚重置还没恢复,都会黑。先点亮、切回前台,等一两秒再截。
跑一段时间后开始失败:九成是没回收。每张 AutoImage 都要 image.recycle(),循环里尤其别漏。
要提速:换成预截图。开一个后台预截图线程,之后每帧只取图,不再走完整截图:
function main() { image.resetCaptureScreenNoAutoEnv(); image.useOpencvMat(1); // types 传 10:PNG 不压缩,不开自动化也能截 image.startPreCapScreen("10", 0, 20);
for (let i = 0; i < 10; i++) { sleep(1000); console.time("stream"); let img = image.captureScreenStream(); logd("取一帧 " + console.timeEnd("stream") + " ms"); if (img != null) image.recycle(img); }
image.stopScreenStream();}
main();USB HID 相关函数
文章里用到的 HID 函数都在这里,点名字跳到文档对应位置:
| 函数 | 用途 | 文档 |
|---|---|---|
usbHidEvent.sessionStart | 开启 HID 会话 | 开启会话 |
usbHidEvent.sessionStop | 关闭会话 | 关闭会话 |
usbHidEvent.sessionRestart | 重置会话,掉线后用 | 重置会话 |
usbHidEvent.setScreenSize | 设置屏幕尺寸,坐标基准 | 设置屏幕尺寸 |
usbHidEvent.clickPoint | 点击坐标 | 点击坐标 |
usbHidEvent.swipeToPoint | 滑动,翻视频用 | 滑动 |
usbHidEvent.press | 长按坐标 | 长按坐标 |
usbHidEvent.touchDown/touchMove/touchUp | 自定义手势轨迹 | 按下 · 移动 · 抬起 |
usbHidEvent.systemKey | 返回、Home 等系统键 | 系统按键 |
截图和 OCR 的函数在另外两个模块:
| 模块 | 函数 | 文档 |
|---|---|---|
| 截图 | image.captureFullScreenNoAuto、resetCaptureScreenNoAutoEnv、startPreCapScreen、captureScreenStream | image-api |
| OCR | ocr.newOcr、ocr.initOcr、ocrImage | ocr-api |
完整的 HID 函数列表见 USB HID 事件 API。
关于我们:EasyClick 做手机自动化脚本开发和群控,覆盖安卓免 ROOT、iOS 免越狱、鸿蒙。USB HID 的会话、点击、输入、截图四段代码在 苹果群控免签名脚本实战:USB HID 四段代码拆解;截图函数的完整参数见 image-api 文档。