news 2026/9/13 3:57:55

MaaAssistantArknights 远程控制协议实战:基于 getTask / reportStatus 双端点的轮询式任务调度实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MaaAssistantArknights 远程控制协议实战:基于 getTask / reportStatus 双端点的轮询式任务调度实现

MaaAssistantArknights 远程控制协议实战:基于 getTask / reportStatus 双端点的轮询式任务调度实现

【免费下载链接】MaaAssistantArknights《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients.项目地址: https://gitcode.com/GitHub_Trending/ma/MaaAssistantArknights

本文基于 MaaAssistantArknights(MAA)仓库中的远程控制协议文档,完整讲解如何搭建一套 HTTP 服务来远程控制 MAA 实例:你需要理解"获取任务端点(getTask)+ 汇报任务端点(reportStatus)"这一双端点轮询架构、各类任务 type 的取值与执行语义(顺序任务 vs 立即任务),并结合 GUI 端源码(RemoteControlService.cs)了解轮询、去重、双队列调度与结果上报的底层实现,最终能独立开发 QQBot、Web 控制台等第三方远程控制后端。

一、协议总览:MAA 是被轮询的"执行端"

MAA 的远程控制协议是一种**客户端轮询式(Pull-based)**设计:MAA 本身不对外暴露端口、不需要回调地址,它只会做两件事——

  1. 定时轮询你提供的"获取任务端点",拉取要执行的任务列表;
  2. 任务执行完毕后,向"汇报任务端点" POST 执行结果。

因此,要实现远程控制,控制方(你的服务器)必须提供一个 http(s) 服务,并且该服务提供两个可匿名访问的 web 端点。两个端点的路径可以随意命名,例如:

https://your-control-host.net/maa/getTask https://your-control-host.net/maa/reportStatus

被控 MAA 需要分别把这两个地址填写到设置界面"远程控制"页签的获取任务端点汇报任务端点文本框中。

两个关键的安全与格式注意事项(原文档明确强调):

  • 如果端点使用 http 明文协议,MAA 会在每次连接时发出不安全警告。在公网部署明文传输服务非常危险,官方文档仅建议测试环境使用。源码中这一点由 RemoteControlService.cs 的IsEndpointValid实现:https://直接通过;http://会弹出"连接端点未启用 https,可能不安全"的提示但仍返回有效;非 http(s) 地址则判定为无效。
  • JSON 文件不支持注释,协议文档中的注释仅用于演示说明,实际返回的 JSON 中不能携带注释。

二、获取任务端点(getTask):请求与响应格式

2.1 请求格式

MAA 以固定间隔持续轮询该端点,默认间隔 1 秒,可在设置中调整(对应配置项RemoteControlPollIntervalMs,默认值 1000ms,见 RemoteControl.cs)。

端点必须能够接受一个Content-Type=application/json的 POST 请求,请求体至少包含以下字段:

{ "user": "ea6c39eb-a45f-4d82-9ecc-33a7bf2ae4dc", // 用户在 MAA 设置中填写的用户标识符 "device": "f7cd9682-3de9-4eef-9137-ec124ea9e9ec" // MAA 自动生成的设备标识符 }
  • user是用户自己填写的任意标识(如 QQ 号、网站账号密钥);
  • device由 MAA 自动生成,可在界面中"重新生成"(源码实现为Guid.NewGuid().ToString("N"),见 RemoteControlService.cs);
  • 如果端点还有其他用途,你可以自行添加可选参数,但MAA 只会传递 user 和 device 两个字段,不会传更多。

2.2 响应格式:任务列表

端点必须返回 JSON 格式的 Response,且必须包含tasks数组(不存在 tasks 字段视为连接无效)。完整示例如下(注释仅供阅读):

{ "tasks": [ // —— 顺序执行的任务:按下发顺序排队执行 —— { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "CaptureImage" // 截图任务:截取当前模拟器的一张截图,以 Base64 字符串放在汇报任务的 payload 里。 // 注意:截图可能有数十 MB,若端点部署在网关之后,务必调大网关允许的最大请求体大小。 }, { "id": "15be4725-5bd3-443d-8ae3-0a5ae789254c", "type": "LinkStart" // 启动"一键长草" }, { "id": "15be4725-5bd3-443d-8ae3-0a5ae789254c", "type": "LinkStart-Recruiting" // 立即根据当前配置,单独执行一键长草中的对应子功能, // 无视主界面上该功能的勾选框。可选 Type 见下表。 }, { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "Toolbox-GachaOnce" // 工具箱抽卡任务,可选值:Toolbox-GachaOnce、Toolbox-GachaTenTimes }, { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "Settings-ConnectAddress", "params": "value" // 修改配置项任务,等同于设置连接设置中的 ConnectAddress 属性。 // 出于安全考虑并非所有配置都可以远程修改,可选值见下表。 }, // —— 立即执行任务:可穿插在顺序任务运行中,MAA 保证其尽快返回 —— { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "CaptureImageNow" // 立刻截图:与普通截图任务基本相同,区别是不会排队等待其他任务 }, { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "StopTask" // "结束当前任务":尝试停止当前运行的任务。若队列中还有其他任务会继续执行下一个。 // 该任务不等待确认停止完成就返回,因此需用 HeartBeat 确认停止是否生效。 }, { "id": "b353c469-b902-4357-bd8f-d133199eea31", "type": "HeartBeat" // 心跳任务:立即返回,并把顺序任务队列中"正在执行"的任务 Id 作为 payload 返回; // 若当前没有任务在执行,返回空字符串。 } ] }

除了tasks之外的其他返回字段 MAA 不会读取,你可以根据自身业务自由扩展。

2.3 任务 type 完整取值表

type执行类别说明
CaptureImage顺序执行截图排队执行,截图 PNG 的 Base64 随汇报 payload 返回
LinkStart顺序执行启动一键长草(按当前配置执行全部已勾选功能)
LinkStart-Base顺序执行单独执行基建,无视主界面勾选框
LinkStart-WakeUp顺序执行单独执行启动(WakeUp)
LinkStart-Combat顺序执行单独执行作战(Combat)
LinkStart-Recruiting顺序执行单独执行公招(Recruiting)
LinkStart-Mall顺序执行单独执行贸易站(Mall)
LinkStart-Mission顺序执行单独执行赏金(Mission)
LinkStart-AutoRoguelike顺序执行单独执行自动集成战略
LinkStart-Reclamation顺序执行单独执行物资回收站
Toolbox-GachaOnce顺序执行工具箱牛牛抽卡(单抽)
Toolbox-GachaTenTimes顺序执行工具箱牛牛抽卡(十连)
Settings-ConnectAddress顺序执行修改连接地址配置(params为新值)
Settings-Stage1顺序执行修改第一作战任务的关卡(params为关卡号)
CaptureImageNow立即执行立刻截图,不等待队列中的其他任务
StopTask立即执行请求停止当前任务,不等待确认
HeartBeat立即执行立即返回,payload 为当前正在执行的顺序任务 Id(空闲时为空字符串)

执行顺序的语义要点:

  • 顺序任务严格按下发顺序排队。例如先下发一个公招任务再下发一个截图任务,截图会在公招结束后执行;
  • 立即执行任务可以穿插在顺序任务运行期间,MAA 保证这类任务尽快返回,通常用于远程控制功能本身的控制(截图、停止、心跳);多个立即任务之间也按下发顺序执行,但执行速度都很快,一般无需关心;
  • Settings-*系列任务仍是顺序执行,不会在收到时立刻生效,而是排在前一个任务之后;
  • 端点应当可以重入(允许反复轮询)且重复返回相同任务也没关系:MAA 会自动记录已入队的任务 id,相同 id 不会重复执行
  • 未知 type 会被 MAA 直接忽略(源码中会解锁一个"404"成就彩蛋)。

三、汇报任务端点(reportStatus):结果上报

每当 MAA 执行完一个任务,就会向该端点 POST 一次执行结果。端点路径同样随意,例如https://your-control-host.net/maa/reportStatus

端点必须能够接受一个Content-Type=application/json的 POST 请求,请求体格式为:

{ "user": "ea6c39eb-a45f-4d82-9ecc-33a7bf2ae4dc", // 用户标识符 "device": "f7cd9682-3de9-4eef-9137-ec124ea9e9ec", // 设备标识符 "task": "15be4725-5bd3-443d-8ae3-0a5ae789254c", // 要汇报的任务 Id,与下发时的 id 对应 "status": "SUCCESS", // 任务执行结果:SUCCESS 或 FAILED "payload": "" // 汇报时携带的数据,字符串类型 }
  • status一般不论任务执行成功与否都返回SUCCESS,只有特殊情况才返回FAILED(哪些情况会 FAILED,协议在对应任务介绍中会明确说明,例如截图失败);
  • payload具体内容取决于任务类型:截图任务汇报时,payload 携带截图的 Base64 字符串;HeartBeat任务则携带当前正在执行的顺序任务 Id。

该端点的返回内容任意:MAA 不会读取返回内容,也不校验状态码;汇报请求失败时 MAA 只会在日志中记录错误,不会重试或阻塞后续任务。因此后端实现时可以把该接口做得非常"无脑"——接收并落库即可。

四、源码解析:MAA 端如何调度这些任务

GUI 端的全部远程控制逻辑集中在 RemoteControlService.cs,理解它可以帮助你精确把握协议语义。

4.1 三个并行轮询循环

服务初始化时(InitializePollJobTask,RemoteControlService.cs)会启动三个无限循环,每个循环都以RemoteControlPollIntervalMs为节拍:

循环职责
PollJobTaskLoop向 getTask 端点 POST{user, device},解析tasks数组并入队
ExecuteSequentialJobLoop从顺序队列取出任务执行,执行完向 reportStatus 上报
ExecuteInstantJobLoop从立即队列取出任务执行,执行完向 reportStatus 上报

这就是文档所说"立即执行任务可以在顺序任务运行中执行"的机制来源——立即任务走独立队列和独立循环,与顺序队列互不阻塞。

4.2 任务入队与 id 去重

PollJobTaskLoop中,对每个下发的任务先取type(空则跳过),再用_enqueueTaskIds列表做去重(RemoteControlService.cs):

  • LinkStartLinkStart-*Toolbox-*CaptureImageSettings-*进入_sequentialTaskQueue
  • CaptureImageNowHeartBeatStopTask进入_instantTaskQueue
  • 已见过的 id 直接跳过——这就是"相同 id 不会重复执行"的去重实现,也意味着你可以放心地让 getTask 重入并重复返回历史任务;
  • 无法识别的 type 不会入队,而是解锁一个NotFound404成就(源码中的小彩蛋)。

4.3 各任务的执行细节

ExecuteSequentialJobLoop的 switch 分支(RemoteControlService.cs)可以看到每类任务的实际行为:

  • LinkStart / LinkStart-*:先等待当前实例进入空闲(_runningState.UntileIdleAsync),随后调用私有的LinkStart方法。该方法与主界面"一键长草"按钮行为一致,但只执行指定子集:连接模拟器 → 按名称(Base/WakeUp/Combat/Recruiting/Mall/Mission/AutoRoguelike/Reclamation)序列化对应任务配置 →AsstStart启动 → 再次等待空闲。对LinkStart-XX类型,它直接取type.Split('-')[1]得到子功能名,完全绕过主界面的勾选框,这正是文档所说"无视主界面上该功能的勾选框"的实现。
  • Toolbox-GachaOnce / GachaTenTimes:等待空闲后分别调用ToolboxViewModel.GachaOnce()/GachaTenTimes(),完成后再次等待空闲。
  • CaptureImage / CaptureImageNow:先AsstConnect建立连接,再用AsstGetFreshImageAsync抓取一帧图像,经PngBitmapEncoder编码为 PNG 字节流后 Base64 放入 payload;连接失败或取图失败则status = "FAILED"。两类截图任务的代码路径几乎相同,区别仅在走哪个队列。
  • Settings-ConnectAddress:把params写入SettingsViewModel.ConnectSettings.ConnectAddress
  • Settings-Stage1:把params写入第一作战任务FightTask.StagePlan[0].Stage(若作战方案不止一个,会先清空只保留一个)。

两个值得注意的实现事实:

  • 上报请求的字段名是task而非idnew { user, device, status, task = id, payload }),与你后端收到的task字段一致;
  • StopTask 的"不等待确认"语义在源码中体现得很直白:调用AsstStop()后注释明确写着"无需等待,甩出任务即可返回,远端应该用心跳来确认界面卡死和取消是否成功"。
  • HeartBeat 的 payload就是成员变量_currentSequentialTaskId——即顺序队列当前正在执行的任务 id;没有任务时为空字符串。这为远端提供了判断"MAA 是否卡死在某任务"的探针:持续轮询 HeartBeat,若 payload 长期不变且 StopTask 后仍不变,即可判定执行端无响应。

4.4 连接测试、端点校验与设备标识

设置页面上的"测试连接"按钮绑定到RemoteControlService.ConnectionTest(RemoteControlService.cs):它向 getTask 端点发送一次与真实轮询相同格式的 POST 请求(Accept: application/json),只看 HTTP 状态码——非 2xx 就弹出"连接测试失败,原因: {状态码}",异常则弹出异常信息,成功则提示"连接测试成功!"。这意味着你的后端只需保证 getTask 对"合法用户"返回 200(哪怕 tasks 为空),测试连接就能通过。

界面侧还有两个与协议相关的能力(RemoteControlUserControl.xaml):

  • 设备标识符为只读文本框,旁边有"重新生成"按钮;
  • 界面上方有固定提示:"随意填入未知来源的地址可能会导致您的账户受到损失"——远程控制端点拥有执行任务、修改配置的权限,只应指向自己信任的服务

另外一个本地安全细节:四个文本框的输入值(两个端点、用户标识、设备标识)在写入本地配置文件前会经 SimpleEncryptionHelper 使用系统数据保护 API(DPAPI,CurrentUser 范围)加密存储(见 RemoteControlUserControlModel.cs)。这只保护本地配置文件不被直接读取明文,网络传输层面的安全仍然依赖你选择 https。

五、MAA 客户端的配置步骤

作为被控端,配置流程如下(对应设置界面"远程控制"页签):

  1. 获取任务端点填入 getTask 的完整 http(s) 地址;
  2. 汇报任务端点填入 reportStatus 的完整 http(s) 地址;
  3. 用户标识符中填写你自定义的标识(如 QQ 号、网站密钥);
  4. 从只读的设备标识符文本框复制 MAA 自动生成的 device id 并发送给你的后端;
  5. 如需调整轮询频率,可修改轮询间隔 (ms),默认 1000ms;
  6. 点击测试连接验证后端可达性。

界面还提供了一个指向远程控制开发者文档的链接(URL 常量见 MaaUrls.cs),方便开发者直接查阅本协议。

六、范例工作流一:用 QQBot 控制 MAA

文档给出了一个完整的 QQBot 控制场景,其核心思路是利用 getTask 请求天然携带 user/device 的特性,把轮询请求兼职当作"注册与认证"通道

  1. 开发者部署后端,暴露两个端点:https://myqqbot.com/maa/getTaskhttps://myqqbot.com/maa/reportStatus
  2. getTask 接口不管收到什么参数都默认返回 200OK 和空的 tasks 列表
  3. 每次收到 getTask 请求时,后端检查数据库里有没有重复的 device:没有,就把该 device 与 user 记录入库。该接口由此同时承担了用户注册功能;
  4. Bot 提供一条 QQ 指令,让用户提交自己的 deviceId。使用说明告诉用户:在 MAA 的用户标识符中填写自己的 QQ 号,再把设备标识符通过 QQ 聊天发给 Bot;
  5. Bot 收到标识符后,按消息中的 QQ 号(user)在数据库查找记录。找不到,则提示用户先去配置 MAA。由于 MAA 配置好后会持续发轮询请求,只要用户填对了 user 与 device,数据库里必然有匹配记录;
  6. 匹配成功后,Bot 给该记录打上"已验证"标记。此后 getTask 再收到这套 device + user 请求时,才返回真正的任务列表;
  7. 用户在 QQ 上提交指令后,Bot 将一条任务写入数据库,稍后 getTask 轮询即可拉到它。该 Bot 还在每次提交指令后默认追加一个截图任务
  8. MAA 执行完任务后调用 reportStatus 汇报结果,Bot 收到后在 QQ 端发送消息通知用户并展示截图。

这个工作流展示了协议的三个实用特性:空 tasks + 200 可作为"握手未通过"的通用响应;轮询请求可兼作设备注册;截图任务 + reportStatus 的 payload 天然构成"执行结果可视化"闭环。

七、范例工作流二:用网站批量管理 MAA

第二个场景是通过自有网站的批量管理,与 QQBot 例子的区别在于认证模型:

  1. 网站暴露https://mywebsite.com/maa/getTaskhttps://mywebsite.com/maa/reportStatus
  2. 网站自带用户管理系统,界面上有"连接 MAA 实例"功能:展示一个开发者称之为用户密钥的随机字符串,并提供填入设备 id 的文本框;
  3. 用户要求:在 MAA 的用户标识符中填写自己的用户密钥,把设备标识符填入网站;
  4. 只有网站上成功创建了 MAA 连接(密钥 + device 配对登记)后,getTask 才返回 200OK,其他情况一律返回 401Unauthorized。这样如果用户在 MAA 上填错了密钥或设备 id,按下"测试连接"按钮就会得到失败提示,形成即时反馈;
  5. 用户即可在网站上为任意实例下发任务、排队、查看截图——实现方式与 QQBot 例子相同,全部通过 getTask / reportStatus 两个端点组合完成。

八、后端实现的要点清单

综合协议文档与源码行为,开发一个符合规范的 MAA 远程控制后端需要满足:

要求说明
端点协议必须 http(s);公网务必使用 https,否则 MAA 每次连接都会报警告
getTask接受匿名 POST,请求体含userdevice;响应必须含tasks数组,空闲时返回空数组并给 200
可重入getTask 会被以 1 秒(默认)为间隔反复轮询,必须幂等、无状态或可从数据库重建任务列表;重复返回相同 id 是安全的
任务去重MAA 侧已按 id 去重,后端只需维护"待下发任务"集合,下发后可保留(MAA 不会重复执行)或移除
reportStatus接受user/device/task/status/payload;返回内容 MAA 完全不读取,按"fire and forget"处理
大报文截图任务汇报的 payload 是 PNG 的 Base64,可达数十 MB,需调大网关/反代的 body 大小限制
停止确认StopTask 不保证停止完成,需用 HeartBeat 轮询确认当前执行任务 id 变化或为空
认证策略参考两个范例:空 tasks + 200(QQBot 式注册)或 401 拦截(网站式密钥校验),二者都能与"测试连接"按钮正确配合

【免费下载链接】MaaAssistantArknights《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients.项目地址: https://gitcode.com/GitHub_Trending/ma/MaaAssistantArknights

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 3:53:01

多目标跟踪中的数据关联算法详解与工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:51:15

如何设置 calibre 从添加书籍的文件名推断标题和作者等元数据

如何设置 calibre 从添加书籍的文件名推断标题和作者等元数据 【免费下载链接】calibre The official source code repository for the calibre ebook manager 项目地址: https://gitcode.com/GitHub_Trending/ca/calibre calibre 在添加书籍时默认从电子书文件内部读取…

作者头像 李华
网站建设 2026/9/13 3:49:11

国家基因组科学数据中心核心资源与应用解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:45:27

LSTM-Adaboost在电力负荷预测中的优化应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华