JSXHook 内置 MCP 工具总览
JSXHook 内置 MCP 工具总览
这一页把 JSXHook 当前真正内置注册的 22 个 MCP 工具 一次性列全,不再只看 APK 分析那 12 个。
它们来自两处注册入口:
core/mcp/JsxHookMcpServerManager.kt:10 个工作区、脚本、运行时工具core/mcp/ApkAnalysisMcpTools.kt:12 个 APK 分析工具
如果你前面觉得“怎么只看到 12 个”,问题就出在这里:以前这页只单列了 APK 分析工具,没有把另外 10 个工作区 / 运行时工具并进来。现在这一页按真实注册结果重新整理成完整总表。
先记住两个容易踩坑的点:
- 工具名要按注册名原样写。
比如listProjects就是驼峰,list_files就是下划线,不能混着写。 - 布尔值尽量传真正的 JSON 布尔值。
比如true/false,不要写成字符串"true"/"false"。有些字段虽然能兼容字符串,有些却不会按你想的方式生效。
先分清这两类
| 类别 | 数量 | 命名风格 | 典型用途 |
|---|---|---|---|
| 工作区与运行时工具 | 10 | camelCase | 列项目、读写代码、管理多脚本、启动宿主、看日志 |
| APK 分析工具 | 12 | snake_case | 浏览工作区、读 Smali、查类、查方法、查引用 |
全部 22 个工具一览
工作区与运行时工具(10 个)
| 工具名 | 用途 |
|---|---|
listProjects | 列出当前 JSXHook 工作区里的项目、作用域和启动配置 |
listAppScripts | 列出多脚本管理里的宿主应用与脚本 |
readCode | 读取项目文件或多脚本文件 |
writeCode | 写入项目文件或多脚本文件 |
replaceCode | 在现有代码里做字符串替换 |
createDirectory | 在项目里创建目录 |
launchTargetApp | 启动宿主应用,并在启动前尝试强制停止 |
getHookState | 查看框架连接、作用域、最近 Hook 线索和错误 |
getRuntimeLogs | 读取最近运行日志和 Probe 线索 |
clearRuntimeLogs | 清空运行日志和 Probe 线索 |
APK 分析工具(12 个)
| 工具名 | 用途 |
|---|---|
get_analysis_state | 获取 APK 缓存、索引进度和活动工作区状态 |
list_apk_workspaces | 列出缓存中的 APK 工作区 |
list_files | 列出 APK 工作区里的目录或文件 |
search_code | 搜索类、方法、字段、字符串常量 |
read_file | 读取 Smali 文件或 Manifest 内容 |
get_method_content | 按方法名从 Smali 文件里提取方法体 |
get_class_info | 按 Smali 文件读取类元数据 |
inspect_class | 快速查看类的宏观结构 |
find_usages | 查找类或方法的引用位置 |
get_manifest | 读取 AndroidManifest.xml 和基础包信息 |
get_class_by_descriptor | 按类描述符直接定位类 |
get_method_by_signature | 按方法签名直接定位方法 |
工作区与运行时工具(10 个)
listProjects
用途
列出当前 JSXHook 工作区里的所有项目。适合先摸底“现在本机工作区里到底有哪些项目、作用域写了什么、启动宿主指向谁”。
参数
这个工具没有参数。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projects | object[] | 当前工作区里的项目数组 |
projects[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 项目名 |
enabled | boolean | 项目当前是否启用 |
author | string | 项目作者;没写时可能是空字符串 |
description | string | 项目描述;没写时可能是空字符串 |
scope | string[] | 项目作用域列表;常见是具体包名数组,也可能包含 all |
launcher | string | 项目显式指定的宿主包名;为空字符串时表示没有单独指定 |
initPath | string | 项目 init.js 的工作区相对路径;实际常见形如 /Project/项目名/init.js |
mainPath | string | 项目 main.js 的工作区相对路径;实际常见形如 /Project/项目名/main.js |
示例
{
"name": "listProjects",
"arguments": {}
}
返回示例
{
"ok": true,
"message": "已返回项目列表",
"result": {
"projects": [
{
"name": "Demo",
"enabled": true,
"author": "admin",
"description": "示例项目",
"scope": [
"org.autojs.autojspro"
],
"launcher": "org.autojs.autojspro",
"initPath": "/Project/Demo/init.js",
"mainPath": "/Project/Demo/main.js"
}
]
}
}
补充说明
- 如果返回
projects: [],表示当前工作区里还没有项目。 - 这个工具只读,不会修改任何内容。
listAppScripts
用途
查看多脚本管理里有哪些宿主应用,以及每个宿主下面挂了哪些脚本。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
packageName | string | 否 | 宿主应用包名 | 精确指定某个宿主应用 |
appName | string | 否 | 应用名关键字 | 不传 packageName 时可用它匹配应用 |
参数规则
packageName和appName同时传时,packageName优先。- 两个都不传时,会读取当前多脚本配置里已经登记过的宿主应用列表。
appName的匹配顺序是:- 先把它当包名精确匹配
- 再把它当应用名精确匹配
- 最后做包含式模糊匹配
- 如果模糊匹配到多个应用,会直接报错,不会擅自帮你选一个。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
apps | object[] | 多脚本宿主应用数组;每个元素代表一个宿主应用及其脚本列表 |
apps[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
packageName | string | 宿主应用包名 |
appName | string | 宿主应用显示名 |
scripts | object[] | 这个宿主下面登记的脚本数组 |
apps[].scripts[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 脚本名,不一定带 .js 后缀 |
enabled | boolean | 当前脚本是否启用 |
description | string | 脚本说明;没填时可能是空字符串 |
version | string | 当前脚本版本标记;常见会看到 v1.0 |
path | string | 工作区里的脚本相对路径;实际常见形如 /AppScript/包名/脚本名.js |
示例
按应用名筛一个宿主:
{
"name": "listAppScripts",
"arguments": {
"appName": "Auto.js"
}
}
按包名精确筛:
{
"name": "listAppScripts",
"arguments": {
"packageName": "org.autojs.autojspro"
}
}
返回示例
{
"ok": true,
"message": "已返回多脚本列表",
"result": {
"apps": [
{
"packageName": "org.autojs.autojspro",
"appName": "Auto.js",
"scripts": [
{
"name": "demo",
"enabled": true,
"description": "登录流程示例",
"version": "v1.0",
"path": "/AppScript/org.autojs.autojspro/demo.js"
}
]
}
]
}
}
补充说明
- 如果当前没有配置任何多脚本宿主,可能会返回空列表。
- 这个工具不会读取脚本正文,只列出配置与路径。
readCode
用途
读取项目文件或多脚本文件内容,并同时返回纯文本和 Base64,方便 MCP 客户端后续继续编辑或转存。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
targetType | string | 是 | project、appScript | 目标类型。代码层还兼容 appscript、app_script、app-script |
projectName | string | 条件必填 | 项目名 | targetType=project 时必填 |
file | string | 否 | 默认 main.js | 仅 project 使用;支持 main、main.js、init、init.js、以及任意项目内相对路径 |
packageName | string | 条件必填 | 包名 | targetType=appScript 时可用 |
appName | string | 条件必填 | 应用名 | targetType=appScript 时可用;和 packageName 二选一即可 |
scriptName | string | 条件必填 | 脚本名 | targetType=appScript 时必填,写不写 .js 都行 |
参数规则
targetType=project时,必须给projectName。targetType=appScript时,必须能解析出宿主应用包名,并且必须给scriptName。file留空时,默认就是项目根下的main.js。scriptName末尾如果写了.js,内部会自动去掉后缀再定位脚本。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
targetType | string | 返回值不是你传入的原样字符串,而是内部解析后的目标类型;当前实际常见值是 project 或 app_script |
projectName | string | null | 目标是项目文件时有值;多脚本时通常为 null |
packageName | string | null | 目标是多脚本时有值;项目文件时通常为 null |
appName | string | null | 目标是多脚本时,解析出来的宿主应用显示名 |
scriptName | string | null | 目标是多脚本时,解析后的脚本名 |
path | string | 本地绝对路径;实际就是 /data/local/tmp/JSXHook/... 下面的真实文件 |
relativePath | string | 相对路径;项目目标时是项目内相对路径,如 modules/test.js,多脚本目标时常见是 /AppScript/... |
content | string | UTF-8 正文文本 |
contentBase64 | string | 同一份 content 的 Base64 版本 |
示例
读取项目 main.js:
{
"name": "readCode",
"arguments": {
"targetType": "project",
"projectName": "Demo"
}
}
读取项目 init.js:
{
"name": "readCode",
"arguments": {
"targetType": "project",
"projectName": "Demo",
"file": "init"
}
}
读取多脚本:
{
"name": "readCode",
"arguments": {
"targetType": "appScript",
"packageName": "org.autojs.autojspro",
"scriptName": "demo"
}
}
返回示例
{
"ok": true,
"message": "代码已读取",
"result": {
"targetType": "app_script",
"projectName": null,
"packageName": "org.autojs.autojspro",
"appName": "Auto.js",
"scriptName": "demo",
"path": "/data/local/tmp/JSXHook/AppScript/org.autojs.autojspro/demo.js",
"relativePath": "/AppScript/org.autojs.autojspro/demo.js",
"content": "toast('ok');",
"contentBase64": "dG9hc3QoJ29rJyk7"
}
}
补充说明
- 项目文件路径会被限制在该项目目录内部,越界路径会直接报错。
- 多脚本读取时,如果脚本不存在,会报
未找到脚本 ...。
writeCode
用途
写入项目文件或多脚本文件。这个工具既可以改已有文件,也可以新建项目内文件或多脚本。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
targetType | string | 是 | project、appScript | 代码层还兼容 appscript、app_script、app-script |
projectName | string | 条件必填 | 项目名 | targetType=project 时必填 |
file | string | 否 | 默认 main.js | 仅 project 使用 |
packageName | string | 条件必填 | 包名 | targetType=appScript 时可用 |
appName | string | 条件必填 | 应用名 | targetType=appScript 时可用 |
scriptName | string | 条件必填 | 脚本名 | targetType=appScript 时必填 |
content | string | 三选一 | 纯文本 | 适合短内容 |
contentBase64 | string | 三选一 | Base64 文本 | 适合长代码 |
lines | array | 三选一 | 字符串数组 | 会按换行拼接成文本 |
description | string | 否 | 仅多脚本有效 | 创建或更新多脚本描述 |
enabled | boolean | 否 | 仅多脚本有效 | 创建或更新多脚本启用状态 |
内容优先级
如果你同时传了多种写入内容,内部优先级是:
contentcontentBase64lines
所以实际使用时,最好只传其中一种,避免自己以为写进去的是 A,实际生效的是 B。
行为细节
- 写项目文件时,如果父目录不存在,会自动创建父目录。
- 写多脚本时,如果脚本还不存在,会直接创建。
- 写多脚本时,
description和enabled会写回脚本配置。 - 新建多脚本配置时,如果没有旧版本号,会默认写成
v1.0。 - 新建多脚本时,如果你没显式传
enabled,当前实现会沿用旧值;如果连旧配置都没有,默认等价于启用状态true。 - 新建多脚本时,如果你没传
description,默认是空字符串。 enabled这里最好传真正的 JSON 布尔值;字符串"false"在当前实现里不会按布尔覆盖处理。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
path | string | 写入目标的本地绝对路径 |
relativePath | string | 写入目标的相对路径;项目目标时是项目内相对路径,多脚本目标时常见是 /AppScript/... |
size | number | 本次写入内容的字符长度;注意这里是字符串长度,不是文件字节数 |
示例
直接写项目 main.js:
{
"name": "writeCode",
"arguments": {
"targetType": "project",
"projectName": "Demo",
"content": "log('hello');"
}
}
返回示例
{
"ok": true,
"message": "代码已写入",
"result": {
"path": "/data/local/tmp/JSXHook/AppScript/org.autojs.autojspro/mcp-demo.js",
"relativePath": "/AppScript/org.autojs.autojspro/mcp-demo.js",
"size": 12
}
}
按行写项目文件:
{
"name": "writeCode",
"arguments": {
"targetType": "project",
"projectName": "Demo",
"file": "modules/test.js",
"lines": [
"function test() {",
" return 1;",
"}"
]
}
}
创建多脚本并启用:
{
"name": "writeCode",
"arguments": {
"targetType": "appScript",
"packageName": "org.autojs.autojspro",
"scriptName": "mcp-demo",
"content": "toast('ok');",
"description": "MCP 写入示例",
"enabled": true
}
}
补充说明
- 如果
content、contentBase64、lines一个都不传,会直接报错。 contentBase64传错格式时,解码会失败。
replaceCode
用途
在已有代码里做字符串替换。适合小范围修补,不适合大改结构。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
targetType | string | 是 | project、appScript | 目标类型;代码层还兼容 appscript、app_script、app-script |
projectName | string | 条件必填 | 项目名 | targetType=project 时必填 |
file | string | 否 | 默认 main.js | 仅 project 使用 |
packageName | string | 条件必填 | 包名 | targetType=appScript 时可用 |
appName | string | 条件必填 | 应用名 | targetType=appScript 时可用 |
scriptName | string | 条件必填 | 脚本名 | targetType=appScript 时必填 |
search | string | 是 | 非空字符串 | 要查找的原始文本 |
replace | string | 是 | 任意字符串 | 替换后的文本;可以是空字符串,表示删除 |
replaceAll | boolean | 否 | 默认 false | 是否替换全部匹配 |
行为细节
replaceAll=false时,只替换第一个匹配。replaceAll=true时,替换全部匹配。- 匹配方式是普通字符串匹配,不是正则。
- 如果找不到
search,会直接报错,不会静默成功。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
path | string | 被替换文件的本地绝对路径 |
replacedAll | boolean | 表示本次是否按“全量替换模式”执行;它表示执行模式,不表示到底替换了多少处 |
示例
只替换第一个:
{
"name": "replaceCode",
"arguments": {
"targetType": "project",
"projectName": "Demo",
"search": "foo()",
"replace": "bar()"
}
}
返回示例
{
"ok": true,
"message": "代码已替换",
"result": {
"path": "/data/local/tmp/JSXHook/Project/Demo/main.js",
"replacedAll": true
}
}
全部替换:
{
"name": "replaceCode",
"arguments": {
"targetType": "project",
"projectName": "Demo",
"search": "debug = true",
"replace": "debug = false",
"replaceAll": true
}
}
补充说明
- 这个工具内部会先完整读取原文件,再替换,再整文件写回。
- 要做复杂重构时,更适合先
readCode再由 Agent 或脚本生成新内容后配合writeCode。
createDirectory
用途
在项目里创建目录,常用于先把模块目录搭出来,比如 utils/crypto、pages/login、lib/http。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
projectName | string | 是 | 已存在的项目名 | 目标项目 |
path | string | 是 | 项目内相对目录路径 | 可以是多级目录 |
行为细节
path必须是项目内相对路径。- 路径越界会报错,不允许跳出项目根目录。
- 多级目录会一起创建。
- 如果目录本来就已经存在,当前实现也会按成功返回,不会因为“已存在”而报错。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectName | string | 本次创建目录所属的项目名 |
path | string | 新目录的本地绝对路径;实际位于 /data/local/tmp/JSXHook/Project/... |
relativePath | string | 你传入的项目内相对目录路径 |
示例
{
"name": "createDirectory",
"arguments": {
"projectName": "Demo",
"path": "utils/crypto"
}
}
返回示例
{
"ok": true,
"message": "目录已创建",
"result": {
"projectName": "Demo",
"path": "/data/local/tmp/JSXHook/Project/Demo/utils/crypto",
"relativePath": "utils/crypto"
}
}
补充说明
- 这个工具只创建目录,不会顺便创建文件。
launchTargetApp
用途
按项目、多脚本或直接按包名/应用名启动宿主应用。启动前会先尝试 am force-stop,然后再拉起宿主。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
targetType | string | 否 | 默认 app | 可填 project、appScript、app;实现层还兼容 appscript、app_script、app-script |
projectName | string | 条件必填 | 项目名 | targetType=project 时使用 |
packageName | string | 条件必填 | 包名 | targetType=app / appScript 时可用;project 时也可作为覆盖值 |
appName | string | 条件必填 | 应用名 | 可用来解析包名 |
目标解析规则
targetType=project时,宿主包名的选择顺序是:- 你显式传入的
packageName - 项目的
launcher - 项目
scope里第一个不等于all的包名
- 你显式传入的
targetType=appScript时,会按packageName/appName解析宿主。targetType=app或不传targetType时,也是按packageName/appName解析。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
packageName | string | 最终用于启动的宿主包名 |
appName | string | 最终解析出的宿主应用显示名 |
component | string | 最终启动的 package/activity 组件短名 |
launchMethod | string | 当前实现常见值是 shell_am_start 或 context_startActivity |
shellMode | string | 当前执行 shell 的模式名 |
forceStopOk | boolean | 启动前那次 am force-stop 是否成功;它不等于“应用一定成功启动” |
shellOutput | string | null | shell 启动输出;可能是 am start -W 的返回文本,也可能为空 |
launchMethod 常见值
shell_am_start:通过 shell 的am start -W成功启动context_startActivity:shell 方式不理想或失败后,回退到context.startActivity(...)
示例
按项目启动:
{
"name": "launchTargetApp",
"arguments": {
"targetType": "project",
"projectName": "Demo"
}
}
按包名直接启动:
{
"name": "launchTargetApp",
"arguments": {
"packageName": "org.autojs.autojspro"
}
}
返回示例
{
"ok": true,
"message": "宿主应用已启动",
"result": {
"packageName": "org.autojs.autojspro",
"appName": "Auto.js",
"component": "org.autojs.autojspro/.ui.splash.SplashActivity",
"launchMethod": "shell_am_start",
"shellMode": "ROOT",
"forceStopOk": true,
"shellOutput": "Status: ok"
}
}
补充说明
- 这个工具不是“单纯 startActivity 一下”,它会先强停,再尽量用 shell 的
am start -W启动。 - 如果 shell 启动失败,会回退到
context.startActivity(...)。 - 如果宿主没有 launcher Activity,或者系统无法解析启动 Intent,会报错。
getHookState
用途
看当前 Hook 环境是不是通的,框架名和版本是什么,目标包有没有进作用域,最近有没有 Probe 线索和错误。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
packageName | string | 否 | 包名 | 直接指定目标包 |
appName | string | 否 | 应用名 | 用它解析目标包 |
targetType | string | 否 | 常用 project | 文案里主要写了 project;当前实现也能容忍 app / appScript 形式 |
projectName | string | 否 | 项目名 | targetType=project 时可用 |
行为细节
- 这个工具可以不传任何参数,当成“全局环境诊断”来用。
- 如果你传了目标,但目标包解析失败,这个工具也不一定直接抛错;它可能仍然返回全局状态,只是
targetPackage为null。
返回字段
| 字段 | 类型 | 典型值 | 说明 |
|---|---|---|---|
shellMode | string | 例如某个 Shell 模式枚举名 | 当前用于执行 shell 的模式名,主要给你排查“为什么 shell 行为不一致” |
serviceConnected | boolean | true / false | 当前 Xposed / LSPosed 侧服务是否已连上 |
targetPackage | string | null | org.autojs.autojspro | 本次诊断针对的目标包;没传目标或目标解析失败时可能是 null |
targetScopeGranted | boolean | null | true / false / null | 目标包是否已经在当前授予作用域里;只有 targetPackage 有值时才真正有意义 |
grantedScope | string[] | 包名数组 | 当前框架已授予的全部包名列表 |
frameworkName | string | null | 例如某个框架名 | 当前读取到的框架名称;读不到时为 null |
frameworkVersion | string | null | 例如版本号字符串 | 当前读取到的框架版本;读不到时为 null |
lastProbeLine | string | 一条 Probe 日志 | 最近一条 Probe 线索;没有时通常是空字符串 |
lastHookProbeLine | string | 一条 Hook Probe 日志 | 最近一条更偏 Hook 侧的 Probe 线索;没有时通常为空 |
lastErrorLine | string | 一条错误日志 | 最近一条错误相关日志;没有时通常为空字符串 |
recentErrors | string[] | 最多 12 条 | 最近筛出来的错误日志数组,当前实现只取末尾最多 12 条 |
lastRequestStatus | string | IDLE、APPROVED 等 | 最近一次作用域请求状态 |
lastRequestMessage | string | 任意文本 | 最近一次作用域请求的附带说明、错误信息或状态说明;没有时为空字符串 |
lastRequestStatus 可选值
这个字段不是随便拼出来的字符串,而是源码里的枚举值,当前可选项有:
IDLE:还没有发生过明确的作用域请求REQUESTING:正在请求作用域APPROVED:请求已通过FAILED:请求失败SERVICE_UNAVAILABLE:服务当前不可用ERROR:出现异常
示例
直接看全局状态:
{
"name": "getHookState",
"arguments": {}
}
看某个宿主包的作用域状态:
{
"name": "getHookState",
"arguments": {
"packageName": "org.autojs.autojspro"
}
}
返回示例
{
"ok": true,
"message": "Hook 状态已返回",
"result": {
"shellMode": "ROOT",
"serviceConnected": true,
"targetPackage": "org.autojs.autojspro",
"targetScopeGranted": true,
"grantedScope": [
"org.autojs.autojspro",
"com.example.demo"
],
"frameworkName": "LSPosed",
"frameworkVersion": "1.9.3",
"lastProbeLine": "[Probe] login() entered",
"lastHookProbeLine": "[HookProbe] before invoke login",
"lastErrorLine": "",
"recentErrors": [],
"lastRequestStatus": "APPROVED",
"lastRequestMessage": "Scope already granted"
}
}
补充说明
targetScopeGranted只有在成功解析出目标包时才有意义;没目标时通常是null。- 这个工具很适合排查“脚本写了但为什么没有实际 Hook 到”的问题。
getRuntimeLogs
用途
读取最近的运行日志,还可以把 Probe 线索一起带回来。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
limit | number | 否 | 默认 80,实际会被限制在 1 到 400 | 最多返回多少条 |
keyword | string | 否 | 任意关键字 | 按关键字过滤 |
packageName | string | 否 | 包名 | 按包名过滤 |
appName | string | 否 | 应用名 | 不传 packageName 时可用它解析包名 |
includeProbe | boolean | 否 | 默认 false | 是否把 Probe 日志也一起返回 |
行为细节
packageName和appName同时传时,packageName优先。appName解析规则和前面一样,存在模糊匹配与多结果报错的情况。- 内部读取日志时,不是扫描无限历史,而是先取一批最近可见日志,再做过滤。
- 当前实现有一个很关键的小细节:
如果你指定了packageName,但过滤后一条都没有,它会回退成“只按关键字过滤”,而不是死板地返回空数组。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
packageName | string | null | 实际用于过滤的包名;没传或没解析成功时可能为 null |
keyword | string | null | 实际用于过滤的关键字;没传时为 null |
runtimeLogs | string[] | 过滤后的运行日志数组;当前实现返回的是过滤结果里的末尾最多 limit 条 |
probeLogs | string[] | 过滤后的 Probe 日志数组;只有 includeProbe=true 时才会有内容 |
示例
读取某个宿主最近 100 条日志并带上 Probe:
{
"name": "getRuntimeLogs",
"arguments": {
"packageName": "org.autojs.autojspro",
"limit": 100,
"includeProbe": true
}
}
按关键字筛日志:
{
"name": "getRuntimeLogs",
"arguments": {
"keyword": "login",
"limit": 50
}
}
返回示例
{
"ok": true,
"message": "运行日志已返回",
"result": {
"packageName": "org.autojs.autojspro",
"keyword": "login",
"runtimeLogs": [
"[JSXHook][Info] login start",
"[JSXHook][Info] login success"
],
"probeLogs": [
"[Probe] enter login()"
]
}
}
补充说明
includeProbe=false时,probeLogs通常就是空数组。limit超过 400 也不会真的返回 400 以上,内部会被压到 400。
clearRuntimeLogs
用途
把当前运行日志和 Probe 线索一起清空,适合重新调试前先“清台面”。
参数
这个工具没有参数。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
runtimeLogsCleared | boolean | 运行日志是否已清空;正常成功时应为 true |
probeLogsCleared | boolean | Probe 线索是否已清空;正常成功时应为 true |
示例
{
"name": "clearRuntimeLogs",
"arguments": {}
}
返回示例
{
"ok": true,
"message": "运行日志已清空",
"result": {
"runtimeLogsCleared": true,
"probeLogsCleared": true
}
}
补充说明
- 这是清空动作,不是筛选动作。
- 清完之后再抓日志,更容易看清楚“本次操作到底打出了哪些新日志”。
APK 分析工具(12 个)
这组工具有 4 个总规则,你最好先记住:
get_analysis_state和list_apk_workspaces可以在没有活动工作区时直接调用。search_code、find_usages这两个工具依赖当前活动工作区,它们本身不收projectDir。- 路径类参数最稳的写法永远是带上
project_xxx/前缀。
虽然部分工具在当前已有活动工作区时可以省略前缀,但为了避免串错工作区,文档都推荐显式写完整。 - 这批工具里的大多数,如果当前还在建索引,或者根本还没选 APK 工作区,不是直接给空结果,而是会返回带指引的
ok=false响应,提示你先去准备工作区。
公共引导返回(ok=false)
很多 APK 分析工具在下面两种场景里,不会马上给业务结果,而是返回一个统一的引导对象:
- 当前 APK 还在建索引
- 当前还没有可用的 APK 工作区
典型返回结构如下:
| 字段 | 类型 | 典型值 | 说明 |
|---|---|---|---|
tool | string | 例如 search_code | 触发引导的工具名 |
needsWorkspace | boolean | true | 表示继续调用前需要准备工作区 |
action | string | open_settings_select_apk | 建议动作标识 |
settingsSection | string | APK analysis cache | 建议你去的设置区块 |
nextStep | string | 一段提示文本 | 下一步怎么操作 |
如果你在客户端里看到 ok=false,先别急着当成“工具坏了”,很多时候只是工作区还没准备好。
返回示例
{
"ok": false,
"message": "No APK cache is available yet. Please open Settings and choose a local APK file first.",
"result": {
"tool": "search_code",
"needsWorkspace": true,
"action": "open_settings_select_apk",
"settingsSection": "APK analysis cache",
"nextStep": "Open Settings -> APK Analysis Cache and select a local APK file."
}
}
get_analysis_state
用途
看当前 APK 缓存是什么状态,有没有活动工作区,索引走到哪一步了,以及缓存里一共挂着几个工作区。
参数
这个工具没有参数。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
state | object | 当前活动工作区状态对象;这是最核心的一块 |
activeWorkspace | object | null | 当前活动工作区摘要;没有活动工作区时可能为 null |
workspaceCount | number | 当前缓存里有多少个 APK 工作区 |
workspaces | object[] | 所有缓存工作区的摘要数组 |
state 字段详解
| 字段 | 类型 | 典型值 | 说明 |
|---|---|---|---|
projectDir | string | null | project_xxx | 当前活动工作区目录名;没有活动工作区时可能为 null |
status | string | IDLE、INDEXING、READY、ERROR | 当前工作区整体状态 |
indexing | boolean | true / false | 当前是否正在建索引 |
progressStage | string | COPYING、PARSING 等 | 当前索引阶段 |
progressPercent | number | 0 到 100 | 当前阶段进度百分比 |
hasWorkspace | boolean | true / false | 当前是否有可用活动工作区 |
isReady | boolean | true / false | 当前活动工作区是否已经 ready |
sourceName | string | 例如 APK 文件名 | 导入源文件名;没有活动工作区时通常为空字符串 |
sourceUri | string | URI 字符串 | 导入时记录的源 URI |
sourceSha256 | string | 一段哈希值 | 源 APK 的 SHA-256 |
packageName | string | com.example.app | APK 包名 |
appLabel | string | 应用名 | APK 应用显示名 |
versionName | string | 1.0.0 | APK 版本名 |
versionCode | number | 1、10086 | APK 版本号 |
cachedApkPath | string | 本地绝对路径 | 缓存后的 APK 文件路径 |
smaliRootPath | string | 本地绝对路径 | 当前工作区 Smali 根目录路径 |
manifestPath | string | 本地绝对路径 | Manifest 文件路径 |
dexCount | number | 非负整数 | Dex 数量 |
classCount | number | 非负整数 | 类数量 |
methodCount | number | 非负整数 | 方法数量 |
fieldCount | number | 非负整数 | 字段数量 |
stringCount | number | 非负整数 | 字符串常量数量 |
refCount | number | 非负整数 | 引用关系数量 |
lastIndexedAt | number | 时间戳 | 最近一次完成索引的 Unix 毫秒时间戳 |
lastError | string | 错误信息 | 最近一次错误信息;没有错误时通常为空字符串 |
status 可选值
IDLE:当前没有可用活动工作区INDEXING:正在建索引READY:工作区可正常使用ERROR:上次索引或读取失败
progressStage 可选值
IDLECOPYINGPREPARINGDISASSEMBLINGPARSINGPERSISTING
activeWorkspace / workspaces[] 摘要字段
这两个对象的字段结构是同一套,区别只是:
activeWorkspace:当前那一个workspaces[]:全部缓存工作区列表
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 工作区名 |
sourceName | string | 源 APK 名 |
packageName | string | APK 包名 |
appLabel | string | 应用显示名 |
versionName | string | 版本名 |
versionCode | number | 版本号 |
indexStatus | string | 当前索引状态,常见 READY / INDEXING / ERROR |
lastError | string | 最近一次错误信息 |
cachedApkPath | string | 缓存 APK 绝对路径 |
smaliRootPath | string | 工作区根路径 |
manifestPath | string | Manifest 路径 |
dexCount | number | Dex 数量 |
classCount | number | 类数量 |
methodCount | number | 方法数量 |
fieldCount | number | 字段数量 |
stringCount | number | 字符串数量 |
refCount | number | 引用数量 |
createdAt | number | 创建时间的 Unix 毫秒时间戳 |
updatedAt | number | 最近更新时间的 Unix 毫秒时间戳 |
lastIndexedAt | number | 最近索引完成时间的 Unix 毫秒时间戳 |
示例
{
"name": "get_analysis_state",
"arguments": {}
}
返回示例
{
"ok": true,
"message": "APK 分析状态已返回",
"result": {
"state": {
"projectDir": "project_demo",
"status": "READY",
"indexing": false,
"progressStage": "IDLE",
"progressPercent": 0,
"hasWorkspace": true,
"isReady": true,
"sourceName": "demo.apk",
"sourceUri": "content://apk/demo.apk",
"sourceSha256": "abc123",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"cachedApkPath": "/apkcache/project_demo/source.apk",
"smaliRootPath": "/apkcache/project_demo",
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"dexCount": 2,
"classCount": 860,
"methodCount": 7421,
"fieldCount": 1948,
"stringCount": 3288,
"refCount": 12004,
"lastIndexedAt": 1715000000000,
"lastError": ""
},
"activeWorkspace": {
"projectDir": "project_demo",
"sourceName": "demo.apk",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"indexStatus": "READY",
"lastError": "",
"cachedApkPath": "/apkcache/project_demo/source.apk",
"smaliRootPath": "/apkcache/project_demo",
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"dexCount": 2,
"classCount": 860,
"methodCount": 7421,
"fieldCount": 1948,
"stringCount": 3288,
"refCount": 12004,
"createdAt": 1714999999000,
"updatedAt": 1715000000000,
"lastIndexedAt": 1715000000000
},
"workspaceCount": 1,
"workspaces": [
{
"projectDir": "project_demo",
"sourceName": "demo.apk",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"indexStatus": "READY",
"lastError": "",
"cachedApkPath": "/apkcache/project_demo/source.apk",
"smaliRootPath": "/apkcache/project_demo",
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"dexCount": 2,
"classCount": 860,
"methodCount": 7421,
"fieldCount": 1948,
"stringCount": 3288,
"refCount": 12004,
"createdAt": 1714999999000,
"updatedAt": 1715000000000,
"lastIndexedAt": 1715000000000
}
]
}
}
补充说明
- 这是 APK 分析链路里最适合第一个调的工具。
- 如果你看到
status=INDEXING,后面很多读取类工具暂时都不该急着调。
list_apk_workspaces
用途
列出当前缓存中的 APK 工作区,方便你确认到底缓存了哪些 APK,以及当前激活的是哪一个。
参数
这个工具没有参数。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
activeProjectDir | string | null | 当前活动工作区名;没有活动工作区时可能为 null |
workspaceCount | number | 当前缓存中的工作区数量 |
workspaces | object[] | 工作区摘要数组 |
workspaces[] 字段
workspaces[] 的字段结构和上面 get_analysis_state 里的 activeWorkspace / workspaces[] 摘要对象相同,最常看的仍然是:
projectDirsourceNamepackageNameappLabelversionNameversionCodeindexStatuslastError
indexStatus 可选值
READYINDEXINGERROR
示例
{
"name": "list_apk_workspaces",
"arguments": {}
}
返回示例
{
"ok": true,
"message": "APK 工作区列表已返回",
"result": {
"activeProjectDir": "project_demo",
"workspaceCount": 1,
"workspaces": [
{
"projectDir": "project_demo",
"sourceName": "demo.apk",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"indexStatus": "READY",
"lastError": "",
"cachedApkPath": "/apkcache/project_demo/source.apk",
"smaliRootPath": "/apkcache/project_demo",
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"dexCount": 2,
"classCount": 860,
"methodCount": 7421,
"fieldCount": 1948,
"stringCount": 3288,
"refCount": 12004,
"createdAt": 1714999999000,
"updatedAt": 1715000000000,
"lastIndexedAt": 1715000000000
}
]
}
}
补充说明
- 如果你缓存过多个 APK,这个工具特别适合先把它们列出来,再决定后面要查哪一个。
list_files
用途
列出 APK 工作区里的目录或文件,适合先在 smali/、smali_classes2/、AndroidManifest.xml 这些入口之间浏览。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
projectDir | string | 是 | 形如 project_xxx | 工作区目录名 |
relativePath | string | 否 | 默认根目录 | 工作区内相对路径 |
路径规则
relativePath为空时,列工作区根目录。- 推荐写相对路径,比如
smali/com/example。 - 即使你把
relativePath写成project_xxx/smali/com/example,内部也会尽量帮你剥掉前缀。 - 如果
relativePath指到的是一个文件而不是目录,当前实现返回的是它所在父目录的列表,不是文件内容。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 你传入的工作区名 |
relativePath | string | 你传入的相对路径;为空字符串时表示根目录 |
text | string | 面向人阅读的简短目录文本,比如 [DIR] smali、[FILE] AndroidManifest.xml |
entries | object[] | 结构化目录项数组 |
entries[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 目录项显示名 |
path | string | 目录项在工作区里的相对路径 |
kind | string | 目录项类型 |
isDirectory | boolean | 是否为目录 |
kind 常见值
DIRSMALIMANIFEST
示例
列根目录:
{
"name": "list_files",
"arguments": {
"projectDir": "project_xxx"
}
}
列某个包目录:
{
"name": "list_files",
"arguments": {
"projectDir": "project_xxx",
"relativePath": "smali/com/example"
}
}
返回示例
{
"ok": true,
"message": "已返回文件列表",
"result": {
"projectDir": "project_demo",
"relativePath": "smali/com/example",
"text": "[FILE] MainActivity.smali\n[FILE] Utils.smali",
"entries": [
{
"name": "MainActivity.smali",
"path": "smali/com/example/MainActivity.smali",
"kind": "SMALI",
"isDirectory": false
},
{
"name": "Utils.smali",
"path": "smali/com/example/Utils.smali",
"kind": "SMALI",
"isDirectory": false
}
]
}
}
补充说明
- 想读文件正文时,用
read_file,不要拿list_files代替。
search_code
用途
在当前活动工作区里搜索类、方法、字段和字符串常量。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
query | string | 是 | 非空关键字 | 搜索词 |
匹配行为
- 这是包含式搜索,不是整词匹配。
- 当前实现会搜索 4 类对象:
CLASSMETHODFIELDSTRING
- 结果会按
filePath -> lineNumber -> kind -> signature排序。
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | null | 当前活动工作区名;理论上正常可用时应有值 |
query | string | 你传入的搜索词 |
text | string | 面向人阅读的搜索摘要文本,每行类似 [METHOD] ... @ file:line |
hits | object[] | 结构化命中数组 |
hits[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
kind | string | 命中类型,当前可选 CLASS、METHOD、FIELD、STRING |
signature | string | 命中的完整签名或字符串内容 |
filePath | string | 命中所在文件的相对路径 |
lineNumber | number | 命中行号 |
示例
{
"name": "search_code",
"arguments": {
"query": "login"
}
}
返回示例
{
"ok": true,
"message": "已返回搜索结果",
"result": {
"projectDir": "project_demo",
"query": "login",
"text": "[METHOD] Lcom/example/Utils;->login(Ljava/lang/String;)V @ smali/com/example/Utils.smali:42",
"hits": [
{
"kind": "METHOD",
"signature": "Lcom/example/Utils;->login(Ljava/lang/String;)V",
"filePath": "smali/com/example/Utils.smali",
"lineNumber": 42
}
]
}
}
补充说明
- 这个工具没有
projectDir参数,所以你得先保证当前活动工作区就是你想查的那个。 - 如果你已经知道完整类描述符或方法签名,直接用
get_class_by_descriptor/get_method_by_signature会更准。
read_file
用途
读取指定工作区文件的正文。最常见的是读 .smali 文件,也可以读 AndroidManifest.xml。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
path | string | 是 | 工作区文件路径 | 最稳的写法是 project_xxx/... |
路径规则
- 推荐写完整路径,例如:
project_xxx/smali/com/example/MainActivity.smaliproject_xxx/AndroidManifest.xml
- 如果当前已经有活动工作区,也可以只写相对路径;但为了不串工作区,不推荐省略。
行为细节
- 读取 Smali 内容时,会清理掉
.line这类调试指令,方便你直接阅读。 - 读 Manifest 时,也会返回文本正文。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
path | string | 你传入的路径 |
content | string | 读取到的正文文本;Smali 会先清理掉 .line 等调试指令 |
示例
读取 Smali:
{
"name": "read_file",
"arguments": {
"path": "project_xxx/smali/com/example/MainActivity.smali"
}
}
返回示例
{
"ok": true,
"message": "已读取文件",
"result": {
"path": "project_demo/AndroidManifest.xml",
"content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.example.demo\" />"
}
}
读取 Manifest:
{
"name": "read_file",
"arguments": {
"path": "project_xxx/AndroidManifest.xml"
}
}
补充说明
- 想看结构化 Manifest 信息时,优先
get_manifest。 - 想提单个方法体时,优先
get_method_content或get_method_by_signature。
get_method_content
用途
当你只知道方法名,不知道完整签名时,用它从某个 Smali 文件里提一个方法体出来。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
filePath | string | 是 | Smali 文件路径 | 推荐完整写成 project_xxx/... |
methodName | string | 是 | 方法名 | 支持精确名和包含匹配 |
匹配规则
- 先做忽略大小写的精确方法名匹配
- 如果精确匹配不到,再做包含匹配
- 候选结果会按
startLine再按methodSignature排序 - 真正返回给你的主结果是排序后的第一个,全部候选同时会放在
candidates里
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 当前工作区名 |
filePath | string | 目标 Smali 文件相对路径 |
classDescriptor | string | null | 当前文件对应的类描述符 |
method | object | 最终选中的那个方法对象;字段结构和 get_method_by_signature 里的 method 相同 |
candidates | object[] | 所有候选方法数组;字段结构也和 method 相同 |
content | string | 最终选中方法的方法体正文 |
text | string | 和 content 相同的兼容字段 |
示例
{
"name": "get_method_content",
"arguments": {
"filePath": "project_xxx/smali/com/example/MainActivity.smali",
"methodName": "onCreate"
}
}
返回示例
{
"ok": true,
"message": "已提取方法",
"result": {
"projectDir": "project_demo",
"filePath": "smali/com/example/MainActivity.smali",
"classDescriptor": "Lcom/example/MainActivity;",
"method": {
"projectDir": "project_demo",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"methodName": "onCreate",
"descriptor": "(Landroid/os/Bundle;)V",
"returnType": "V",
"parameterTypes": [
"Landroid/os/Bundle;"
],
"accessFlags": "protected",
"filePath": "smali/com/example/MainActivity.smali",
"startLine": 28,
"endLine": 56,
"bodyLineCount": 29
},
"candidates": [
{
"projectDir": "project_demo",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"methodName": "onCreate",
"descriptor": "(Landroid/os/Bundle;)V",
"returnType": "V",
"parameterTypes": [
"Landroid/os/Bundle;"
],
"accessFlags": "protected",
"filePath": "smali/com/example/MainActivity.smali",
"startLine": 28,
"endLine": 56,
"bodyLineCount": 29
}
],
"content": ".method protected onCreate(Landroid/os/Bundle;)V\n .locals 1\n return-void\n.end method",
"text": ".method protected onCreate(Landroid/os/Bundle;)V\n .locals 1\n return-void\n.end method"
}
}
补充说明
- 如果同一个类里有多个同名重载方法,这个工具仍然能用,但你要自己看
candidates。 - 已经知道完整方法签名时,
get_method_by_signature更稳。
get_class_info
用途
按 Smali 文件读取类的结构化元数据,适合你要拿字段、方法、字符串列表继续做程序化处理的时候用。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
filePath | string | 是 | Smali 类文件路径 | 推荐完整写成 project_xxx/... |
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 当前类所在工作区 |
file | object | 这个类文件本身的元数据 |
classInfo | object | 类本体的结构信息 |
fields | object[] | 当前类的字段数组 |
methods | object[] | 当前类的方法数组 |
strings | object[] | 当前类里提取到的字符串常量数组 |
file 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 工作区名 |
relativePath | string | 工作区内相对路径 |
parentPath | string | 父目录相对路径 |
displayName | string | 展示名,通常就是文件名 |
isDirectory | boolean | 这里一般应为 false,因为它是类文件 |
kind | string | 常见为 SMALI |
classDescriptor | string | null | 该文件对应的类描述符 |
byteSize | number | 文件字节数 |
lineCount | number | 行数 |
classInfo 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 工作区名 |
classDescriptor | string | 完整类描述符,如 Lcom/example/MainActivity; |
className | string | 类名 |
packageName | string | 包名 |
filePath | string | 类文件相对路径 |
superClass | string | null | 父类描述符 |
interfaces | string[] | 接口描述符数组 |
sourceFile | string | null | 源文件名标记 |
accessFlags | string | 访问修饰信息,如 public final、abstract 等组合 |
lineNumber | number | 类声明行号 |
fieldCount | number | 字段数量 |
methodCount | number | 方法数量 |
fields[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
fieldSignature | string | 完整字段签名 |
classDescriptor | string | 所属类描述符 |
className | string | 所属类名 |
fieldName | string | 字段名 |
typeDescriptor | string | 字段类型描述符 |
accessFlags | string | 字段访问修饰 |
filePath | string | 所在文件路径 |
lineNumber | number | 字段声明行号 |
initialValue | string | null | 初始值;没有时可能为空 |
methods[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
methodSignature | string | 完整方法签名 |
classDescriptor | string | 所属类描述符 |
className | string | 所属类名 |
methodName | string | 方法名 |
descriptor | string | 方法描述符,不含类前缀 |
returnType | string | 返回值类型 |
parameterTypes | string[] | 参数类型数组,按声明顺序排列 |
accessFlags | string | 方法访问修饰 |
filePath | string | 所在文件路径 |
startLine | number | 方法起始行 |
endLine | number | 方法结束行 |
bodyLineCount | number | 方法体行数 |
strings[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
value | string | 字符串字面量内容 |
classDescriptor | string | 所属类描述符 |
methodSignature | string | null | 所在方法签名;如果无法归属到具体方法,可能为空 |
filePath | string | 所在文件路径 |
lineNumber | number | 出现行号 |
示例
{
"name": "get_class_info",
"arguments": {
"filePath": "project_xxx/smali/com/example/MainActivity.smali"
}
}
返回示例
{
"ok": true,
"message": "已读取类信息",
"result": {
"projectDir": "project_demo",
"file": {
"projectDir": "project_demo",
"relativePath": "smali/com/example/MainActivity.smali",
"parentPath": "smali/com/example",
"displayName": "MainActivity.smali",
"isDirectory": false,
"kind": "SMALI",
"classDescriptor": "Lcom/example/MainActivity;",
"byteSize": 4182,
"lineCount": 156
},
"classInfo": {
"projectDir": "project_demo",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"packageName": "com.example",
"filePath": "smali/com/example/MainActivity.smali",
"superClass": "Landroid/app/Activity;",
"interfaces": [],
"sourceFile": "MainActivity.java",
"accessFlags": "public",
"lineNumber": 1,
"fieldCount": 1,
"methodCount": 3
},
"fields": [
{
"projectDir": "project_demo",
"fieldSignature": "Lcom/example/MainActivity;->title:Ljava/lang/String;",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"fieldName": "title",
"typeDescriptor": "Ljava/lang/String;",
"accessFlags": "private",
"filePath": "smali/com/example/MainActivity.smali",
"lineNumber": 8,
"initialValue": null
}
],
"methods": [
{
"projectDir": "project_demo",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"methodName": "onCreate",
"descriptor": "(Landroid/os/Bundle;)V",
"returnType": "V",
"parameterTypes": [
"Landroid/os/Bundle;"
],
"accessFlags": "protected",
"filePath": "smali/com/example/MainActivity.smali",
"startLine": 28,
"endLine": 56,
"bodyLineCount": 29
}
],
"strings": [
{
"projectDir": "project_demo",
"value": "hello",
"classDescriptor": "Lcom/example/MainActivity;",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"filePath": "smali/com/example/MainActivity.smali",
"lineNumber": 39
}
]
}
}
补充说明
- 这个工具要求目标文件真的是 Smali 类文件;如果你塞的是别的路径,会报错。
inspect_class
用途
快速看一个类的整体结构。名字更偏“先浏览一下”,适合从陌生类开始看继承、字段、方法列表。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
path | string | 是 | Smali 类文件路径 | 推荐完整写成 project_xxx/... |
返回结构
这个工具当前返回的结构和 get_class_info 完全同形,也就是同样会返回:
projectDirfileclassInfofieldsmethodsstrings
示例
{
"name": "inspect_class",
"arguments": {
"path": "project_xxx/smali/com/example/MainActivity.smali"
}
}
返回示例
{
"ok": true,
"message": "已读取类结构",
"result": {
"projectDir": "project_demo",
"file": {
"relativePath": "smali/com/example/MainActivity.smali",
"displayName": "MainActivity.smali",
"kind": "SMALI"
},
"classInfo": {
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"superClass": "Landroid/app/Activity;",
"interfaces": [],
"fieldCount": 1,
"methodCount": 3
},
"fields": [
{
"fieldSignature": "Lcom/example/MainActivity;->title:Ljava/lang/String;",
"fieldName": "title",
"typeDescriptor": "Ljava/lang/String;"
}
],
"methods": [
{
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"methodName": "onCreate",
"accessFlags": "protected"
}
],
"strings": [
{
"value": "hello",
"lineNumber": 39
}
]
}
}
补充说明
- 当前实现底层就是走和
get_class_info相同的类快照数据。 - 也就是说,结果结构基本一样;区别主要在于你调用它时的阅读语义:
inspect_class更像“先总览一下”,get_class_info更像“我要结构化数据”。
find_usages
用途
在当前活动工作区里追踪类或方法被谁引用了,适合逆向时找调用点、找入口、找某个类被哪些地方触达。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
signature | string | 是 | 完整类或方法签名 | 例如类描述符或完整方法签名 |
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
signature | string | 你传入的目标签名 |
text | string | 面向人阅读的引用摘要文本,每行类似 [METHOD] source -> target @ file:line |
hits | object[] | 结构化引用数组 |
hits[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
sourceSignature | string | 发起引用的一侧签名 |
targetSignature | string | 你当前查的目标签名,或者与之对应的引用目标 |
filePath | string | 引用出现的文件路径 |
lineNumber | number | 引用出现行号 |
refType | string | 引用类型 |
refType 常见值
CLASSFIELDMETHOD
示例
按方法签名查引用:
{
"name": "find_usages",
"arguments": {
"signature": "Lcom/example/Utils;->login(Ljava/lang/String;)V"
}
}
返回示例
{
"ok": true,
"message": "已返回引用列表",
"result": {
"signature": "Lcom/example/Utils;->login(Ljava/lang/String;)V",
"text": "[METHOD] Lcom/example/MainActivity;->onClickLogin()V -> Lcom/example/Utils;->login(Ljava/lang/String;)V @ smali/com/example/MainActivity.smali:88",
"hits": [
{
"sourceSignature": "Lcom/example/MainActivity;->onClickLogin()V",
"targetSignature": "Lcom/example/Utils;->login(Ljava/lang/String;)V",
"filePath": "smali/com/example/MainActivity.smali",
"lineNumber": 88,
"refType": "METHOD"
}
]
}
}
按类描述符查引用:
{
"name": "find_usages",
"arguments": {
"signature": "Lcom/example/MainActivity;"
}
}
补充说明
- 如果你现在只知道一个模糊关键词,先
search_code,再把搜出来的类描述符或方法签名喂给这里。
get_manifest
用途
读取某个 APK 工作区的 AndroidManifest.xml,同时带回包名、应用名、版本号这些基础信息。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
projectDir | string | 是 | 形如 project_xxx | 工作区目录名 |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 工作区名 |
packageName | string | APK 包名 |
appLabel | string | 应用显示名 |
versionName | string | 版本名 |
versionCode | number | 版本号 |
manifestPath | string | Manifest 文件的本地绝对路径 |
manifestXml | string | Manifest 原始 XML 文本 |
text | string | 和 manifestXml 相同的兼容字段,方便某些客户端统一按 text 读正文 |
示例
{
"name": "get_manifest",
"arguments": {
"projectDir": "project_xxx"
}
}
返回示例
{
"ok": true,
"message": "已读取 Manifest",
"result": {
"projectDir": "project_demo",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"manifestXml": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.example.demo\" />",
"text": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.example.demo\" />"
}
}
补充说明
- 如果你只是想拿原始文本,
read_file读project_xxx/AndroidManifest.xml也能做到。 - 如果你需要包名、版本号、路径这些结构化信息,这个工具更合适。
get_class_by_descriptor
用途
你已经知道完整类描述符时,不想先搜路径,直接一步定位类。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
projectDir | string | 是 | 形如 project_xxx | 目标工作区 |
classDescriptor | string | 是 | 完整类描述符 | 例如 Lcom/example/MainActivity; |
适合场景
- 你已经从
search_code、日志、别的分析工具拿到了类描述符 - 你不想再自己拼
smali/.../*.smali路径
返回结构
这个工具当前返回的结构和 get_class_info 同形,本质上也是一份完整类快照,因此你可以直接按 get_class_info 那套字段表理解:
projectDirfileclassInfofieldsmethodsstrings
示例
{
"name": "get_class_by_descriptor",
"arguments": {
"projectDir": "project_xxx",
"classDescriptor": "Lcom/example/MainActivity;"
}
}
返回示例
{
"ok": true,
"message": "类已定位",
"result": {
"projectDir": "project_demo",
"file": {
"relativePath": "smali/com/example/MainActivity.smali",
"displayName": "MainActivity.smali",
"kind": "SMALI",
"classDescriptor": "Lcom/example/MainActivity;"
},
"classInfo": {
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"packageName": "com.example",
"filePath": "smali/com/example/MainActivity.smali",
"superClass": "Landroid/app/Activity;",
"interfaces": [],
"accessFlags": "public",
"fieldCount": 1,
"methodCount": 3
},
"fields": [
{
"fieldSignature": "Lcom/example/MainActivity;->title:Ljava/lang/String;",
"fieldName": "title"
}
],
"methods": [
{
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"methodName": "onCreate"
}
],
"strings": [
{
"value": "hello",
"lineNumber": 39
}
]
}
}
补充说明
- 这个工具按
projectDir + classDescriptor直接查数据库里的类记录,再回到对应文件抓完整类快照。 - 如果当前还在建索引,会先提示你等待索引完成。
get_method_by_signature
用途
你已经知道完整方法签名时,直接一步拿到方法元数据和方法体。这是定位重载方法时最稳的方式。
参数
| 参数 | 类型 | 必填 | 可填值 / 默认 | 说明 |
|---|---|---|---|---|
projectDir | string | 是 | 形如 project_xxx | 目标工作区 |
methodSignature | string | 是 | 完整方法签名 | 例如 Lcom/example/Utils;->login(Ljava/lang/String;)V |
顶层 result 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 目标工作区 |
methodSignature | string | 你传入的完整方法签名 |
workspace | object | null | 工作区摘要对象;字段结构和上面 get_analysis_state 里的 activeWorkspace 相同 |
filePath | string | 该方法所在 Smali 文件的工作区相对路径 |
method | object | 这个方法本身的结构化信息 |
content | string | 方法体正文 |
text | string | 和 content 相同的兼容字段 |
method 字段
| 字段 | 类型 | 说明 |
|---|---|---|
projectDir | string | 工作区名 |
methodSignature | string | 完整方法签名 |
classDescriptor | string | 所属类描述符 |
className | string | 所属类名 |
methodName | string | 方法名 |
descriptor | string | 方法描述符本体 |
returnType | string | 返回值类型 |
parameterTypes | string[] | 参数类型数组;常见元素如 Ljava/lang/String;、I、Z |
accessFlags | string | 方法访问修饰 |
filePath | string | 所在文件相对路径 |
startLine | number | 当前方法在清洗后文本里的起始行 |
endLine | number | 当前方法在清洗后文本里的结束行 |
bodyLineCount | number | 当前方法正文总行数 |
示例
{
"name": "get_method_by_signature",
"arguments": {
"projectDir": "project_xxx",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V"
}
}
返回示例
{
"ok": true,
"message": "方法已定位",
"result": {
"projectDir": "project_demo",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"workspace": {
"projectDir": "project_demo",
"sourceName": "demo.apk",
"packageName": "com.example.demo",
"appLabel": "Demo",
"versionName": "1.0.0",
"versionCode": 1,
"indexStatus": "READY",
"lastError": "",
"cachedApkPath": "/apkcache/project_demo/source.apk",
"smaliRootPath": "/apkcache/project_demo",
"manifestPath": "/apkcache/project_demo/AndroidManifest.xml",
"dexCount": 2,
"classCount": 860,
"methodCount": 7421,
"fieldCount": 1948,
"stringCount": 3288,
"refCount": 12004,
"createdAt": 1714999999000,
"updatedAt": 1715000000000,
"lastIndexedAt": 1715000000000
},
"filePath": "smali/com/example/MainActivity.smali",
"method": {
"projectDir": "project_demo",
"methodSignature": "Lcom/example/MainActivity;->onCreate(Landroid/os/Bundle;)V",
"classDescriptor": "Lcom/example/MainActivity;",
"className": "MainActivity",
"methodName": "onCreate",
"descriptor": "(Landroid/os/Bundle;)V",
"returnType": "V",
"parameterTypes": [
"Landroid/os/Bundle;"
],
"accessFlags": "protected",
"filePath": "smali/com/example/MainActivity.smali",
"startLine": 28,
"endLine": 56,
"bodyLineCount": 29
},
"content": ".method protected onCreate(Landroid/os/Bundle;)V\n .locals 1\n return-void\n.end method",
"text": ".method protected onCreate(Landroid/os/Bundle;)V\n .locals 1\n return-void\n.end method"
}
}
补充说明
- 和
get_method_content相比,这个工具不会先按方法名猜;你给什么完整签名,它就精确找什么。 - 如果你处理的是重载非常多的方法,这个工具通常是首选。
推荐的调用顺序
如果你是第一次接入 JSXHook 的内置 MCP 工具,比较稳的顺序通常是这样:
listProjects/listAppScripts
先摸底本机工作区和多脚本现状。getHookState/getRuntimeLogs
先确认运行环境是通的。get_analysis_state
看 APK 缓存是不是 ready。list_apk_workspaceslist_filessearch_codeinspect_class/get_class_infoget_method_content或get_method_by_signaturefind_usagesget_manifest
和 mcpServer 文档怎么分工
这页回答的是:
- JSXHook 内置都注册了哪些 MCP 工具
- 每个工具叫什么、参数能填什么、什么时候该用它
而 mcpServer 对象 那页回答的是:
- 你自己怎么在脚本里开 MCP 服务
- 你自己怎么注册 Tool / Resource / Prompt
- 协议、端口、生命周期、路由和状态怎么理解
所以最实用的搭配方式通常是:
- 先在 mcpServer 对象 看“服务怎么开”
- 再回这页看“内置已经有哪些现成工具可以直接调”
