在当前移动应用和智能设备高度普及的背景下,自动化脚本被广泛应用于测试、辅助操作乃至批量任务处理等场景。然而,传统的自动化手段——尤其是依赖Android系统无障碍服务(Accessibility Service)的技术——由于其对用户界面的深度介入和行为模式的高度可预测性,极易被应用端的风控系统识别并拦截。许多金融、社交及游戏类App通过检测无障碍服务的启用状态、调用频率、操作路径异常等方式,有效识别并阻止非人工操作,从而限制了基于无障碍技术的自动化方案的可行性与稳定性。
为规避此类风控机制,一种更具隐蔽性和底层控制能力的替代方案逐渐受到关注:蓝牙HID(Human Interface Device)技术。该技术通过模拟真实的蓝牙输入设备(如键盘、鼠标),将自动化指令以标准HID协议的形式发送至目标设备,使其在操作系统层面被视为合法的人机交互行为。由于这类操作不依赖于应用层API,也不触发无障碍服务相关的权限或日志记录,因此更难被上层应用察觉。此外,HID通信通常走的是系统级驱动通道,其行为特征与真实用户操作高度一致,进一步降低了被风控模型标记的风险。
采用蓝牙HID实现自动化的典型架构包括一个主控设备(如树莓派、ESP32模块等)和目标终端(如手机或平板),两者通过配对建立低功耗蓝牙连接后,主控即可发送按键、滑动等指令。这种方式不仅提升了自动化脚本的隐蔽性与抗检测能力,也增强了跨平台兼容性。当然,该方案在硬件成本、部署复杂度和响应延迟方面存在一定挑战,但在对安全性与稳定性要求较高的场景中,蓝牙HID技术无疑提供了一条绕过传统风控的有效路径,代表了自动化技术向更底层、更仿人方向演进的新趋势。
一、准备工作
- 硬件准备:需配备支持 BLE HID 协议的硬件设备ESPC32,并已烧录兼容冰狐通信协议的固件。
- 手机端:
- 手机需支持蓝牙,并已与 HID 设备完成配对(可在系统蓝牙设置中确认)。
- 冰狐 App 已安装并登录。
- 权限:确保 App 具有蓝牙权限(通常首次调用会自动申请)。
二、使用步骤与示例脚本
步骤 1:连接蓝牙 HID 设备
function main() {
// 替换为你的设备实际的 Service 和 Characteristic UUID
var serviceUUID = 'fe2342e1-d234-fee3-aae4-fe2e342211dc';
var charUUID = 'cf3432fb-d234-fee3-aae4-fe2e342211dc';
var ret = ble.connect(serviceUUID, charUUID, '', 5000); // 可指定设备名前缀和超时
if (ret !== 1) {
console.error('蓝牙连接失败,错误码:', ret);
return;
}
console.log('蓝牙连接成功');
// 执行自动化操作
runAutomation();
}
步骤 2:执行自动化操作(示例)
function runAutomation() {
// 返回桌面
ble.home();
sleep(1000);
// 打开某个App(需配合 launchApp 或手动点击图标)
// 此处假设图标位于 (300, 800)
ble.click(300, 800);
sleep(2000);
// 滑动页面(从下往上)
ble.swipe(500, 1500, 500, 500, 600); // x1,y1 → x2,y2, 持续600ms
sleep(1000);
// 点击某个按钮(如“确定”)
ble.click(600, 1200);
sleep(500);
// 模拟返回键
ble.back();
}
步骤 3:运行脚本
- 将上述代码保存为
.js脚本文件; - 在冰狐 App 中上传或直接编辑该脚本;
- 确保手机已与 HID 设备配对;
- 运行脚本,观察设备是否响应。
三、注意事项
- UUID 必须匹配:
serviceUUID和characteristicUUID需与 HID 硬件固件中定义的一致。 - 坐标适配:不同手机分辨率不同,建议使用
rsScreenWidth/rsScreenHeight动态计算相对坐标(如文档示例中x * 10000 / rsScreenWidth)。 - 延迟控制:HID 指令执行需要时间,务必在关键操作后加入
sleep()避免过快导致失效。 - 无需无障碍权限:蓝牙 HID 方案完全绕过 Android 无障碍服务,可有效规避多数 App 的风控检测。
四、实际可运行代码
下面我来使用冰狐智能辅助中使用蓝牙hid实现快手极速版自动看广告的例子,供大家参考下:
function main() {
requestScreenShot()
var ret = ble.connect('fe2342e1-d234-fee3-aae4-fe2e342211dc', 'cf3432fb-d234-fee3-aae4-fe2e342211dc');
console.log('ret:', ret)
if (1 == ret) {
while (true) {
sleep(randInt(6000, 8000))
if (ocrFindView('txt*:领取奖励').length > 0) {
console.log('找到广告', ocr())
if (ocrFindView('txt*:免费观看').length > 0) {
console.log('有免费观看')
while (true) {
if (ocrFindView('txt*:成功').length > 0) {
console.log('已经找到广告成功')
sleep(randInt(2000, 3000))
if (ocrFindView('txt*:免费观看').length > 0) {
console.log('找到免费观看')
var r = ocrClick('txt*:免费观看', {clickMode: 2})
console.log('蓝牙点击免费观看:', r)
}
break;
}
}
console.log('有免费观看结束')
} else {
console.log('没有免费观看')
var r = ocrClick('txt*:领取奖励', {clickMode: 2})
console.log('点击领取奖励:', r)
var r = ocrClick('txt*:放弃', {clickMode: 2})
console.log('点击放弃:', r)
}
} else {
exitZB()
console.log('没找到广告,滚动')
ble.swipe(randInt(100, 200), randInt(rsScreenHeight - 300, rsScreenHeight - 200), randInt(250, 300), randInt(250, 350));
// ble.swipe(randInt(100, 200), 800, randInt(250, 300), 300);
}
}
}
console.log('结束')
}
function exitZB() {
var ret = ocrFindView('txt:关注')
if (ret.length > 0) {
console.log('找到直播间')
var top = ret.region[1]
var right = rsScreenWidth - 50
ble.click(right, top)
console.log('点击x left:', right, ' top:', top)
var r = ocrClick('txt*:退出直播间', {clickMode: 2})
console.log('点击退出直播间:', r)
}
}

1823

被折叠的 条评论
为什么被折叠?



