简介

TM助手是一款专业的移动开发辅助工具,提供强大的Lua脚本引擎和完善的设备授权管理系统。

系统要求
  • Android 7.0 及以上
  • 需要网络连接
  • 建议2GB以上内存

安装配置

1. 下载安装

下载中心下载最新版本的TM助手APK文件,安装到Android设备上。

2. 注册登录

首次使用需要注册账号:

  • 输入手机号
  • 获取验证码
  • 完成注册

3. 设备激活

联系管理员获取授权码,在应用中激活设备。

快速上手

第一个Lua脚本

创建一个简单的Hello World脚本:

-- hello.lua
print("Hello, TM助手!")

-- 显示Toast消息
toast("欢迎使用TM助手")

-- 获取设备信息
local deviceId = getDeviceId()
print("设备ID: " .. deviceId)

运行脚本

  1. 打开TM助手应用
  2. 在IDE中编写Lua脚本
  3. 点击"运行"按钮
  4. 查看日志输出

初始化模块 (TmInit)

TmInit是所有图色功能的核心模块,必须在使用其他图色模块前调用。它负责初始化屏幕捕获缓冲区。

基本用法

-- 初始化(竖屏模式)
local result = TmInit(0)

-- 初始化(横屏模式)
local result = TmInit(1)

-- 带调试模式(保存截图到文件)
local result = TmInit(0, true)

函数说明

函数 参数 返回值 说明
TmInit(orientation, saveDebug) orientation: 0=竖屏, 1=横屏
saveDebug: 是否保存调试截图(可选,默认false)
table {success, width, height, message} 初始化屏幕捕获,返回屏幕尺寸信息
重要

TmInit 必须在脚本开头调用!所有图色功能(TmCmpColor、TmFindColor、TmTemplateMatch等)都依赖于此初始化。

示例:完整脚本模板

-- 1. 首先初始化(0=竖屏, 1=横屏)
local initResult = TmInit(0)
if not initResult.success then
    print("初始化失败: " .. initResult.message)
    return
end
print("屏幕尺寸: " .. initResult.width .. "x" .. initResult.height)

-- 2. 现在可以使用图色功能了
local result = TmFindColor("100,200,500,800", "#FF0000")
if result.found then
    TmClick(result.points[1].x, result.points[1].y)
end

点击模块 (TmClick)

TmClick模块提供屏幕坐标点击功能,支持ROOT和无障碍服务两种模式。

基本用法

-- 点击屏幕坐标 (500, 1000)
TmClick(500, 1000)

-- 延迟后点击
TmSleep(1000)  -- 等待1秒
TmClick(300, 800)

函数说明

函数 参数 返回值 说明
TmClick(x, y) x: 横坐标
y: 纵坐标
table {success, x, y, message} 点击指定坐标,返回结果表

工作模式

  • ROOT模式:使用input tap命令,速度快,精度高
  • 无障碍模式:使用AccessibilityService,无需ROOT权限
提示

应用会自动检测设备是否ROOT,并选择最佳模式。建议在设置中手动选择模式以获得更好的性能。

示例:连续点击

-- 连续点击5次
for i = 1, 5 do
    TmClick(500, 1000)
    TmSleep(500)  -- 每次点击间隔0.5秒
end

print("点击完成")

颜色比对模块 (TmCmpColor)

TmCmpColor模块用于比较屏幕指定坐标的颜色,常用于判断界面状态。

基本用法

-- 检查坐标 (100, 200) 的颜色是否为红色
local result = TmCmpColor(100, 200, "#FF0000")
if result.match then
    print("颜色匹配")
else
    print("颜色不匹配,实际颜色: " .. result.actualColor)
end

函数说明

函数 参数 返回值 说明
TmCmpColor(x, y, color) x: 横坐标
y: 纵坐标
color: 颜色值"#RRGGBB"
table {success, match, x, y, expectedColor, actualColor, message} 比较单点颜色
TmCmpColorMulti(pointsStr, tolerance) pointsStr: "x1,y1,#color1|x2,y2,#color2|..."
tolerance: 容差(可选,默认10)
table {success, allMatch, matchCount, totalCount, results, message} 批量多点比色(一次截图检查多个点)

返回值字段说明

  • success - 函数是否执行成功
  • match - 颜色是否匹配
  • expectedColor - 期望的颜色值
  • actualColor - 实际检测到的颜色值
性能优化

使用持久化帧缓冲区,截图在内存中完成,性能优异。脚本运行时帧缓冲区会自动维护。

颜色格式

颜色值使用十六进制格式:#RRGGBB

  • #FF0000 - 红色
  • #00FF00 - 绿色
  • #0000FF - 蓝色
  • #FFFFFF - 白色
  • #000000 - 黑色

颜色容差

系统默认颜色容差为10(RGB每个通道),即实际颜色与期望颜色的RGB值相差在10以内都会被认为匹配。

注意

使用前必须先调用 TmInit() 初始化屏幕捕获。非ROOT模式需要屏幕捕获权限。

示例:等待界面加载

-- 等待按钮变为绿色(表示可点击)
local maxWait = 10  -- 最多等待10秒
local waited = 0

while waited < maxWait do
    local result = TmCmpColor(500, 1000, "#00FF00")
    if result.match then
        print("按钮已就绪")
        TmClick(500, 1000)
        break
    end
    
    TmSleep(500)
    waited = waited + 0.5
end

if waited >= maxWait then
    print("等待超时")
end

示例:多点批量比色(推荐)

-- 一次截图检查多个坐标的颜色(性能更好)
local result = TmCmpColorMulti("100,200,#FF0000|300,400,#00FF00|500,600,#0000FF")

if result.allMatch then
    print("所有颜色都匹配!")
else
    print("匹配数量: " .. result.matchCount .. "/" .. result.totalCount)
    -- 遍历每个点的结果
    for i, point in ipairs(result.results) do
        if not point.match then
            print("不匹配: (" .. point.x .. "," .. point.y .. ") 期望:" .. point.expectedColor .. " 实际:" .. point.actualColor)
        end
    end
end

范围找色模块 (TmFindColor)

TmFindColor模块用于在指定的ROI(感兴趣区域)内查找指定颜色的像素点,支持多颜色匹配和自定义容差。

基本用法

-- 在区域 (100,200,500,800) 内查找红色
local result = TmFindColor("100,200,500,800", "#FF0000")

if result.found then
    local point = result.points[1]
    print("找到颜色,坐标: " .. point.x .. ", " .. point.y)
    TmClick(point.x, point.y)
else
    print("未找到颜色")
end

函数说明

函数 参数 返回值 说明
TmFindColor(roi, color, count, useCache, tolerance) roi: 区域"x1,y1,x2,y2"
color: 颜色值,支持单个"#RRGGBB"或多个"{#c1,#c2}"
count: 需要匹配的数量(可选,默认1)
useCache: 是否使用缓存截图(可选,默认false)
tolerance: 颜色容差(可选,默认10)
table {success, found, matchCount, requiredCount, color, points, message} 在ROI区域内查找颜色

返回值字段说明

  • success - 函数是否执行成功
  • found - 是否找到足够数量的匹配点
  • matchCount - 实际匹配到的数量
  • requiredCount - 需要匹配的数量
  • points - 匹配点数组 [{x, y}, ...]

ROI格式

ROI(Region of Interest)使用逗号分隔的四个坐标:"x1,y1,x2,y2"

  • x1, y1 - 左上角坐标
  • x2, y2 - 右下角坐标
  • 示例:"0,0,1080,2400" - 全屏搜索(1080×2400分辨率)
  • 示例:"100,200,500,800" - 局部区域

颜色格式

支持两种颜色格式:

  • 单个颜色:"#FF0000"
  • 多个颜色:{"#FF0000","#00FF00","#0000FF"}"#FF0000,#00FF00"
性能提示
  • 缩小搜索区域可以提高查找速度
  • 使用 useCache=true 可复用上次截图(同一帧多次找色)
  • 使用 C++ OpenCV 优化,比纯 Kotlin 快数倍

颜色容差

默认容差为10,可通过第5个参数自定义。容差范围 0-255,即 RGB 每个通道允许的差值。

示例:查找并点击按钮

-- 在屏幕下半部分查找绿色按钮
local result = TmFindColor("0,1200,1080,2400", "#00FF00")

if result.found then
    local p = result.points[1]
    print("找到绿色按钮: (" .. p.x .. ", " .. p.y .. ")")
    TmClick(p.x, p.y)
    TmSleep(1000)
    print("已点击按钮")
else
    print("未找到绿色按钮")
end

示例:多颜色匹配

-- 查找红色或绿色或蓝色(任意一个即可)
local result = TmFindColor("100,200,500,800", {"#FF0000", "#00FF00", "#0000FF"})

if result.found then
    print("找到颜色: " .. result.color)
    TmClick(result.points[1].x, result.points[1].y)
end

示例:自定义容差和缓存

-- 第一次找色:实时截图
local result1 = TmFindColor("100,200,500,800", "#FF0000", 1, false, 15)

-- 第二次找色:使用缓存截图(同一帧,速度更快)
local result2 = TmFindColor("100,200,500,800", "#00FF00", 1, true, 15)

示例:循环查找

-- 在30秒内不断查找目标颜色
local maxWait = 30
local waited = 0

while waited < maxWait do
    local result = TmFindColor("100,200,500,800", "#FF0000")
    
    if result.found then
        local p = result.points[1]
        print("找到目标,坐标: (" .. p.x .. ", " .. p.y .. ")")
        TmClick(p.x, p.y)
        break
    end
    
    print("未找到,继续搜索...")
    TmSleep(1000)
    waited = waited + 1
end

if waited >= maxWait then
    print("查找超时")
end
注意事项
  • 使用前必须先调用 TmInit() 初始化
  • 非ROOT模式需要屏幕捕获权限
  • 搜索区域坐标不能超出屏幕范围

模板匹配模块 (TmTemplateMatch)

TmTemplateMatch 使用 OpenCV 进行高精度模板匹配,适用于按钮识别、图标定位等场景。

基本用法

-- 在 ROI 区域内匹配"按钮组"模板
local result = TmTemplateMatch("100,200,500,800", "按钮组", 0.8)

if result.success and result.results then
    for i, match in ipairs(result.results) do
        if match.found then
            print("匹配: " .. match.matchedName .. " 坐标: " .. match.globalX .. "," .. match.globalY)
            TmClick(match.globalX, match.globalY)
        end
    end
end

函数说明

函数 参数 返回值 说明
TmTemplateMatch(roi, groupName, threshold, useCache, debugMode) roi: 区域"x1,y1,x2,y2"
groupName: 模板组名称
threshold: 匹配阈值 0.0-1.0(可选,默认0.8)
useCache: 使用缓存截图(可选,默认false)
debugMode: 调试模式,绘制匹配框(可选,默认false)
table {success, matchTimeMs, groupName, results, message} 在ROI区域内匹配模板组

返回值字段说明

  • success - 匹配是否执行成功
  • matchTimeMs - 匹配耗时(毫秒)
  • results - 匹配结果数组,每个元素包含:
    • found - 是否匹配成功
    • matchX, matchY - ROI 内坐标
    • globalX, globalY - 全局屏幕坐标
    • matchWidth, matchHeight - 模板尺寸
    • confidence - 置信度 0.0-1.0
    • matchedName - 匹配的模板名称

模板管理

模板图片通过 TMide 创建和管理:

  1. 在 TMide 中截图
  2. 框选要识别的区域
  3. 保存为模板,指定组名
  4. 模板自动存储在项目的 script/{分辨率}/ 目录
性能优化
  • C++ OpenCV 原生加速,匹配速度 < 10ms
  • 模板加载后自动缓存,后续调用无需重新加载
  • 支持多线程并行匹配多个模板

延时模块 (TmSleep)

TmSleep 是智能延时函数,延时期间会自动暂停帧获取以节省系统资源。

基本用法

-- 等待 1 秒
TmSleep(1000)

-- 等待 0.5 秒
TmSleep(500)

函数说明

函数 参数 返回值 说明
TmSleep(ms) ms: 延时毫秒数 智能延时,自动暂停帧获取
与 sleep() 的区别

TmSleep 会在延时期间暂停屏幕帧获取,减少 CPU 和内存占用。推荐在图色脚本中使用 TmSleep 替代普通 sleep

轮廓检测模块 (TmFindContours)

TmFindContours 使用 OpenCV 检测屏幕上的轮廓,适用于识别按钮边框、图标轮廓等。

基本用法

-- 在 ROI 区域内检测轮廓
local result = TmFindContours("100,200,500,800")

if result.success then
    print("找到 " .. result.count .. " 个轮廓")
    for i, contour in ipairs(result.contours) do
        print("轮廓" .. i .. ": x=" .. contour.x .. " y=" .. contour.y .. 
              " w=" .. contour.width .. " h=" .. contour.height)
    end
end

函数说明

函数 参数 返回值 说明
TmFindContours(roi, minArea, maxArea) roi: 区域"x1,y1,x2,y2"
minArea: 最小面积(可选)
maxArea: 最大面积(可选)
table {success, count, contours, message} 检测ROI区域内的轮廓

悬浮网格窗口 (TmFloatingGrid)

TmFloatingGrid 模块提供悬浮网格窗口功能,可在屏幕上显示自定义的网格信息,支持文字和图片内容,适用于调试信息展示、状态监控等场景。

基本用法

-- 创建 3行4列 的网格窗口 (宽400px, 高300px, 居中显示)
local windowId = TmFloatingGridCreate(400, 300, 3, 4, 0, 0)

-- 显示窗口
TmFloatingGridShow(windowId)

-- 设置单元格文字 (第1行第1列, 红色文字)
TmFloatingGridSetText(windowId, 1, 1, "状态", "#FF0000", 16, "")

-- 设置单元格图片
TmFloatingGridSetImage(windowId, 2, 1, "images/icon.png")

-- 脚本结束时销毁窗口
TmFloatingGridDestroy(windowId)

函数说明

函数 参数 返回值 说明
TmFloatingGridCreate(width, height, rows, cols, x, y) width: 窗口宽度(px)
height: 窗口高度(px)
rows: 网格行数
cols: 网格列数
x, y: 窗口位置 (0,0 表示居中)
windowId (字符串) 创建悬浮网格窗口
TmFloatingGridSetText(windowId, row, col, text, textColor, textSize, bgColor) windowId: 窗口ID
row, col: 行列号 (从1开始)
text: 文字内容
textColor: 文字颜色 "#RRGGBB"
textSize: 文字大小 (0=默认)
bgColor: 背景色 (""=透明)
boolean 设置单元格文字
TmFloatingGridSetTexts(windowId, data) windowId: 窗口ID
data: 批量数据字符串
格式: "row,col,text,color,size,bg;..."
boolean 批量设置多个单元格文字
TmFloatingGridSetImage(windowId, row, col, imagePath) windowId: 窗口ID
row, col: 行列号
imagePath: 图片路径 (相对于项目目录)
boolean 设置单元格图片
TmFloatingGridSetImageBase64(windowId, row, col, base64Data) windowId: 窗口ID
row, col: 行列号
base64Data: Base64编码的图片
boolean 设置单元格图片 (Base64)
TmFloatingGridSetRowHeight(windowId, row, height) windowId: 窗口ID
row: 行号
height: 高度 (0=自动)
boolean 设置指定行的高度
TmFloatingGridSetColWidth(windowId, col, width) windowId: 窗口ID
col: 列号
width: 宽度 (0=自动)
boolean 设置指定列的宽度
TmFloatingGridClearCell(windowId, row, col) windowId, row, col boolean 清空指定单元格
TmFloatingGridClearAll(windowId) windowId: 窗口ID boolean 清空所有单元格
TmFloatingGridShow(windowId) windowId: 窗口ID boolean 显示窗口
TmFloatingGridHide(windowId) windowId: 窗口ID boolean 隐藏窗口 (不销毁)
TmFloatingGridDestroy(windowId) windowId: 窗口ID boolean 销毁窗口
TmFloatingGridDestroyAll() 销毁所有窗口
TmFloatingGridMove(windowId, x, y) windowId, x, y boolean 移动窗口位置
TmFloatingGridResize(windowId, width, height) windowId, width, height boolean 调整窗口大小

特性说明

  • 多窗口支持:可同时创建多个悬浮窗口,通过 windowId 区分
  • 自动布局:默认情况下,行高和列宽自动均分窗口尺寸
  • 自定义尺寸:可通过 SetRowHeight/SetColWidth 指定特定行列的尺寸
  • 拖拽移动:窗口支持手指拖拽移动位置
  • 自动清理:脚本停止时自动销毁所有悬浮窗口
使用场景
  • 调试信息实时展示
  • 脚本运行状态监控
  • 游戏数据统计面板
  • 识别结果可视化展示

示例:状态监控面板

-- 创建 2行3列 的状态监控面板
local windowId = TmFloatingGridCreate(300, 100, 2, 3, 50, 50)
TmFloatingGridShow(windowId)

-- 设置标题行 (第一行固定高度)
TmFloatingGridSetRowHeight(windowId, 1, 30)

-- 设置标题
TmFloatingGridSetText(windowId, 1, 1, "状态", "#FFFFFF", 12, "#333333")
TmFloatingGridSetText(windowId, 1, 2, "次数", "#FFFFFF", 12, "#333333")
TmFloatingGridSetText(windowId, 1, 3, "耗时", "#FFFFFF", 12, "#333333")

-- 主循环中更新数据
local count = 0
while true do
    count = count + 1
    local startTime = os.clock()
    
    -- 执行任务...
    TmSleep(1000)
    
    local elapsed = string.format("%.1fs", os.clock() - startTime)
    
    -- 更新显示
    TmFloatingGridSetText(windowId, 2, 1, "运行中", "#00FF00", 14, "")
    TmFloatingGridSetText(windowId, 2, 2, tostring(count), "#FFFF00", 14, "")
    TmFloatingGridSetText(windowId, 2, 3, elapsed, "#00FFFF", 14, "")
end

示例:批量设置文字

-- 使用批量设置提高效率
local windowId = TmFloatingGridCreate(400, 200, 2, 4, 0, 0)
TmFloatingGridShow(windowId)

-- 批量设置多个单元格 (格式: row,col,text,color,size,bg;...)
TmFloatingGridSetTexts(windowId, 
    "1,1,A,#FF0000,16,;1,2,B,#00FF00,16,;1,3,C,#0000FF,16,;1,4,D,#FFFF00,16,;" ..
    "2,1,E,#FF00FF,16,;2,2,F,#00FFFF,16,;2,3,G,#FFFFFF,16,;2,4,H,#888888,16,"
)
权限要求

悬浮窗口需要"显示在其他应用上层"权限(SYSTEM_ALERT_WINDOW)。首次使用时会自动请求权限。

更多模块

TM助手还提供了更多实用模块,持续更新中...

已支持的高级功能

YOLO 目标检测

TmYolo 模块支持自定义模型

模板匹配

OpenCV 高精度模板匹配

轮廓检测

识别UI元素边界

多点比色

一次截图批量检测多点颜色

多颜色找色

一次搜索多个目标颜色

HTTP/WebSocket

与IDE实时通信

悬浮网格窗口

屏幕信息展示面板

需要新功能?

如果您有新的模块需求,欢迎通过邮件或社区反馈给我们。我们会根据需求优先级进行开发。

Lua基础

变量和数据类型

-- 变量定义
local name = "TM助手"
local version = 1.0
local isActive = true

-- 表(数组/字典)
local arr = {1, 2, 3, 4, 5}
local dict = {
    name = "张三",
    age = 25,
    city = "杭州"
}

函数定义

-- 函数定义
function greet(name)
    return "Hello, " .. name
end

-- 调用函数
local message = greet("TM助手")
print(message)

条件语句

local score = 85

if score >= 90 then
    print("优秀")
elseif score >= 60 then
    print("及格")
else
    print("不及格")
end

循环语句

-- for循环
for i = 1, 10 do
    print(i)
end

-- while循环
local count = 0
while count < 5 do
    print(count)
    count = count + 1
end

Lua API

基础API

函数 说明 示例
toast(message) 显示Toast消息 toast("Hello")
sleep(ms) 延迟执行(毫秒) sleep(1000)
getDeviceId() 获取设备ID local id = getDeviceId()
log(message) 输出日志 log("Debug info")

HTTP请求

-- GET请求
local response = http.get("https://api.example.com/data")
print(response.body)

-- POST请求
local data = {
    name = "张三",
    age = 25
}
local response = http.post("https://api.example.com/user", data)
print(response.statusCode)

文件操作

-- 读取文件
local content = file.read("/sdcard/test.txt")
print(content)

-- 写入文件
file.write("/sdcard/test.txt", "Hello World")

-- 检查文件是否存在
if file.exists("/sdcard/test.txt") then
    print("文件存在")
end

示例代码

示例1:自动签到

-- 自动签到脚本
function autoCheckIn()
    toast("开始自动签到")
    
    -- 模拟点击签到按钮
    click(500, 1000)
    sleep(2000)
    
    -- 检查签到结果
    local result = getText()
    if string.find(result, "签到成功") then
        toast("签到成功!")
        return true
    else
        toast("签到失败")
        return false
    end
end

-- 执行签到
autoCheckIn()

示例2:数据采集

-- 数据采集脚本
function collectData()
    local data = {}
    
    -- 采集数据
    for i = 1, 10 do
        local item = {
            id = i,
            title = getText(100, 200 + i * 100),
            time = os.time()
        }
        table.insert(data, item)
        sleep(500)
    end
    
    -- 保存数据
    local json = JSON.encode(data)
    file.write("/sdcard/data.json", json)
    
    toast("数据采集完成")
end

collectData()

示例3:定时任务

-- 定时任务脚本
function scheduleTask()
    while true do
        local hour = os.date("%H")
        
        -- 每天早上8点执行
        if hour == "08" then
            toast("开始执行任务")
            -- 执行任务逻辑
            doTask()
            -- 等待1小时
            sleep(3600000)
        end
        
        -- 每分钟检查一次
        sleep(60000)
    end
end

function doTask()
    -- 任务逻辑
    print("执行任务...")
end

scheduleTask()

WebSocket

TM助手内置WebSocket服务,用于IDE与设备之间的实时通信。

连接WebSocket

WebSocket服务地址:ws://设备IP:8081

消息格式

{
  "type": "execute",
  "code": "print('Hello')"
}
提示

WebSocket主要用于IDE与设备的通信,一般情况下不需要手动处理。

HTTP服务

TM助手内置HTTP服务,用于接收IDE的脚本执行请求。

服务地址

HTTP服务地址:http://设备IP:8080

执行脚本

POST /execute
{
  "code": "print('Hello World')"
}

调试技巧

日志输出

-- 使用print输出日志
print("调试信息")

-- 使用log函数
log("Debug: " .. tostring(value))

-- 输出表内容
function printTable(t)
    for k, v in pairs(t) do
        print(k .. " = " .. tostring(v))
    end
end

错误处理

-- 使用pcall捕获错误
local success, error = pcall(function()
    -- 可能出错的代码
    local result = riskyOperation()
    return result
end)

if not success then
    print("错误: " .. error)
    toast("操作失败")
end

性能优化

  • 避免在循环中进行耗时操作
  • 合理使用sleep()控制执行频率
  • 及时释放不需要的资源
  • 使用局部变量提高性能