第一个问题:desc()通过描述来获取控件,但有没有方法可以无需提供此控件的完整描述,也可以使用此方法来获取控件?比如现有一个控件的描述为“等待xx秒后点击可以获取xx金币,看的越久赚的越多”,是个很长的描述,而且里面的xx表示一个时刻变化的数字,每一次都不一样。那我就不能用一个固定的字符串来获取此控件了。所以有没有方法可以只写此控件的一部分描述就可以获取到控件?比如descInclude("秒后点击可以获取")就能返回这个控件?hamibot具有类似的函数可调用吗?
第二个问题:关于images.pixel(),这个方法使用之前必须要申请截图权限吗?我调用这个方法以后返回值是-1,是怎么回事?再就是此函数返回的0xAARRGGBB是一个数字还是一个字符串?给我提供一个使用这个方法的完整例子,告诉我返回的颜色值如何单独去获取每个分量?也就是单独分成argb三个分量。

已存档
SilverFox0-6 · 21 天前
第 1 条补充
·
20 天前

为什么0xFFFFFFFF会显示为-1?这个32位整数是什么意思?如果是其他的颜色,返回值又是什么?给我举几个例子比如黑色、蓝色、黄色等颜色,他们的argb值以及返回的值分别都是什么?

第 2 条补充
·
17 天前

有什么方法可以获得当前手机操作系统的全名吗?比如鸿蒙系统的话可以输出鸿蒙2.0之类的。有个属性device.baseOS,直接输出了手机的型号和品牌,没有输出操作系统详细信息,所以有什么方法可以做到吗?

回答

Hamibot AI
1
· 21 天前

第一个问题:模糊匹配控件描述

Hamibot 的 UI 选择器不支持 descInclude(),但提供了完全符合你需求的 descContains() 方法。你不需要提供完整描述,只需传入固定片段即可匹配包含该片段的控件。

除了包含匹配,Hamibot 还提供以下描述匹配方法,可应对不同场景:

  • descContains(str):描述包含指定字符串
  • descStartsWith(str):描述以指定字符串开头
  • descEndsWith(str):描述以指定字符串结尾
  • descMatches(regexp):使用正则表达式匹配(适合更复杂的动态内容)

针对你的场景,直接使用 descContains() 即可:

// 文档地址 https://docs.hamibot.com/
var target = descContains("秒后点击可以获取").findOne(2000);
if (target) {
    toastLog("成功找到控件");
    target.click();
} else {
    toastLog("未找到匹配控件");
}

建议配合 findOne(timeout) 使用,避免控件尚未加载时脚本直接返回 null。


第二个问题:images.pixel() 使用详解

1. 是否必须申请截图权限?

必须申请。images.pixel() 作用于 Image 对象,而获取当前屏幕的 Image 对象需要调用 captureScreen(),该函数强依赖 requestScreenCapture() 授予的截图权限。未授权或授权失败时调用会直接报错或返回无效数据。

2. 为什么返回值是 -1

images.pixel() 返回的是 32 位有符号整数。-1 对应的十六进制是 0xFFFFFFFF(不透明的纯白色)。返回 -1 通常有两种情况:

  • 该坐标点的实际颜色就是白色。
  • 传入的 (x, y) 坐标超出了图片的实际宽高范围,或图片对象已被回收/为空。此时底层也会返回 -1
    请确保坐标满足 0 <= x < img.getWidth()0 <= y < img.getHeight()

3. 返回值是数字还是字符串?

数字(Number)。格式为 0xAARRGGBB 的 32 位整型数值。JavaScript 不区分整型与浮点型,但在底层按 32 位整数处理。

4. 完整示例与 ARGB 分量提取

Hamibot 内置了 colors 模块,可直接安全地解析该数值。你也可以使用位运算。以下为完整兼容示例:

// 文档地址 https://docs.hamibot.com/
if (!requestScreenCapture(true)) {
    toastLog('没有授予 Hamibot 屏幕截图权限');
    hamibot.exit();
}
sleep(1000);

var img = captureScreen();
var x = 100;
var y = 100;

// 校验坐标合法性,防止越界返回 -1
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
    var colorVal = images.pixel(img, x, y);
    toastLog('原始颜色值(十进制): ' + colorVal);

    // 推荐方式:使用内置 colors 模块提取分量
    var a = colors.alpha(colorVal);
    var r = colors.red(colorVal);
    var g = colors.green(colorVal);
    var b = colors.blue(colorVal);
    toastLog('colors模块 -> A:' + a + ' R:' + r + ' G:' + g + ' B:' + b);

    // 备选方式:使用位运算提取分量(结果与上方一致)
    var a2 = (colorVal >> 24) & 0xFF;
    var r2 = (colorVal >> 16) & 0xFF;
    var g2 = (colorVal >> 8) & 0xFF;
    var b2 = colorVal & 0xFF;
    toastLog('位运算解析 -> A:' + a2 + ' R:' + r2 + ' G:' + g2 + ' B:' + b2);
} else {
    toastLog('坐标超出图片范围,请检查 x y 值');
}

// 最佳实践:截图对象使用完毕后务必回收,防止内存泄漏
img.recycle();
hamibot.exit();

最佳实践提示

  • 频繁调用 captureScreen() 会消耗较多性能,若需连续取色,建议只截图一次,多次调用 images.pixel()
  • Rhino 1.7.15 引擎对位运算的支持稳定,但直接使用 colors 模块可读性更高且不易出错。
  • 脚本中涉及图片对象的操作,结束后必须调用 img.recycle() 释放 native 内存,否则长时间运行极易触发 OOM。
ℹ️ 内容由 AI 生成,可能不准确,请注意核实
Hamibot AI
1
· 20 天前

为什么 0xFFFFFFFF 会显示为 -1

这与底层数字存储的补码机制有关。Hamibot 的 JavaScript 引擎(Rhino)与底层 Java 交互时,颜色值被当作 32 位有符号整数(Signed 32-bit Integer) 处理。

32 位有符号整数的最高位(第 31 位)是符号位:0 代表正数,1 代表负数。
0xFFFFFFFF 展开为二进制是 32 个 111111111 11111111 11111111 11111111)。最高位为 1,系统将其识别为负数。在补码规则下,32 位全 1 恰好等于十进制的 -1。这不是异常,而是所有 Alpha 通道 ≥ 128 的颜色在底层环境中的标准表现。

这个 32 位整数是什么意思?

它表示将颜色的四个通道各占 8 位,紧凑打包进一个 32 位数字中,结构为 0xAARRGGBB

  • 位 24~31:Alpha(透明度)
  • 位 16~23:Red(红色)
  • 位 8~15:Green(绿色)
  • 位 0~7:Blue(蓝色)

每个通道取值范围 0~255。当 Alpha ≥ 128(十六进制 0x80)时,最高位必然为 1,返回值就会呈现为负数。

常见颜色返回值对照表

以下以完全不透明(Alpha=255)为例,展示十六进制、ARGB 分量与 images.pixel() 实际返回的十进制值:

颜色 ARGB 分量 (A,R,G,B) 十六进制 0xAARRGGBB 实际返回值(十进制)
白色 255, 255, 255, 255 0xFFFFFFFF -1
黑色 255, 0, 0, 0 0xFF000000 -16777216
红色 255, 255, 0, 0 0xFFFF0000 -65536
绿色 255, 0, 255, 0 0xFF00FF00 -16711936
蓝色 255, 0, 0, 255 0xFF0000FF -16776961
黄色 255, 255, 255, 0 0xFFFFFF00 -256
纯透明 0, 0, 0, 0 0x00000000 0
半透明白 127, 255, 255, 255 0x7FFFFFFF 2147483647(32位最大正数)

换算规律

  • 十六进制 < 0x80000000:直接转为正数十进制。
  • 十六进制 ≥ 0x80000000:十进制 = 十六进制值 - 4294967296
    例如黑色:4278190080 - 4294967296 = -16777216

实际使用建议

负数返回值完全正常,不影响解析。但在脚本中直接比对十进制负数极易出错,建议按以下方式处理:

// 文档地址 https://docs.hamibot.com/
var colorVal = images.pixel(img, x, y);

// 方式1:转为十六进制字符串比对(直观)
// colors.toString() 返回格式为 #AARRGGBB
if (colors.toString(colorVal) === "#ff0000ff") {
    toastLog("匹配到蓝色");
}

// 方式2:提取分量比对(推荐,容错率高)
var r = colors.red(colorVal);
var g = colors.green(colorVal);
var b = colors.blue(colorVal);
if (b > 200 && r < 50 && g < 50) {
    toastLog("判定为蓝色区域");
}
  • 不要尝试手动将负数转回正数再计算,直接使用 colors 模块或位运算即可正确解析。
  • 若需判断颜色近似值,建议提取 ARGB 分量后计算欧氏距离或设置阈值范围,比严格等于更稳定。
ℹ️ 内容由 AI 生成,可能不准确,请注意核实
Hamibot AI
1
· 17 天前

Android 及基于 Android 衍生的系统(如鸿蒙、MIUI、ColorOS 等)并没有提供统一的标准 API 来直接返回“操作系统全名”。device.baseOS 返回的是底层基础构建版本标识,通常包含厂商内部编译代号或硬件平台信息,因此不适合用于展示用户可见的系统名称。

鸿蒙系统(2.0~4.x)为了保持应用兼容性,对外默认声明为 Android。要获取真实的定制系统名称及版本,需要通过读取设备的系统属性(getprop)来实现。Hamibot 提供了 shell() 函数,你可以直接调用它读取厂商私有属性。

完整获取脚本(兼容 Rhino 1.7.15)

// 文档地址 https://docs.hamibot.com/
function getProp(key) {
    var res = shell("getprop " + key);
    if (res && res.code === 0 && res.result) {
        return res.result.trim();
    }
    return "";
}

function getOSFullName() {
    var harmonyVer = getProp("hw_sc.build.os.version") || getProp("ro.harmonyos.version");
    var emuiVer = getProp("ro.build.version.emui");
    var miuiVer = getProp("ro.miui.ui.version.name");
    var colorosVer = getProp("ro.build.version.opporom");
    var vivoVer = getProp("ro.vivo.os.version");
    var androidVer = device.release;

    if (harmonyVer && harmonyVer.length > 0) {
        return "HarmonyOS " + harmonyVer;
    }
    if (emuiVer && emuiVer.length > 0) {
        // 部分华为机型鸿蒙版本会混写在 EMUI 属性中
        if (emuiVer.indexOf("Harmony") !== -1 || emuiVer.indexOf("harmony") !== -1) {
            return "HarmonyOS " + emuiVer.replace(/EmotionUI_|Emui_/gi, "");
        }
        return "EMUI " + emuiVer;
    }
    if (miuiVer && miuiVer.length > 0) {
        return "MIUI " + miuiVer;
    }
    if (colorosVer && colorosVer.length > 0) {
        return "ColorOS " + colorosVer;
    }
    if (vivoVer && vivoVer.length > 0) {
        return "OriginOS/Funtouch " + vivoVer;
    }
    return "Android " + androidVer;
}

var osName = getOSFullName();
toastLog("当前系统: " + osName);

关键说明

  1. 为什么用 getprop:Android 系统在启动时会将硬件、厂商、版本等信息加载到内存属性服务中。shell("getprop key") 是读取这些信息的标准方式,无需 Root 权限即可读取只读属性。
  2. 鸿蒙的识别逻辑:华为设备通常将鸿蒙版本写入 hw_sc.build.os.version。部分旧机型或过渡版本会写在 ro.build.version.emui 中并带有 Harmony 关键字。脚本已做兼容处理。
  3. device.release 的作用:当所有厂商私有属性都为空时(如原生 Android 或小众品牌),脚本会降级返回 Android x.x,保证始终有有效输出。
  4. 性能提示shell() 会 fork 子进程执行命令,耗时约 10~30ms。建议在脚本初始化时调用一次并缓存结果,不要在循环或高频事件中重复调用。

最佳实践建议

  • 如果只需要判断是否为鸿蒙系统,可直接检查 getOSFullName().indexOf("HarmonyOS") !== -1
  • 不同厂商、不同系统大版本可能会更改属性 Key。若你在特定机型上获取为空,可在该手机终端执行 getprop | grep -i "version\|os\|ui" 查看实际存在的属性名,并补充到 getProp() 的读取链中。
  • 脚本中已严格避免箭头函数与默认参数,完全适配 Hamibot 的 Rhino 1.7.15 引擎。
ℹ️ 内容由 AI 生成,可能不准确,请注意核实