Global Objects 全局对象
Global Objects 全局对象
这一页专门讲“脚本运行时已经自动注入了什么”。它不是替代各模块的独立文档,而是帮你先快速判断:
- 某个名字到底是对象、函数,还是动态上下文。
- 哪些值几乎总有,哪些值随场景可能为
null。 - 哪些字段是固定结构,哪些更适合跳到独立模块文档里看。
先记住这 7 条
lpparam、classLoader是 Hook 脚本最核心的固定上下文。context和activity是动态解析出来的,不能假设任何时候一定存在。console是对象,log()/print()是全局函数,这两套都能打日志。showGlobalDialog、showHostDialog、confirm不是三个系统,而是一套实现的不同名字。httpServer和mcpServer都是对象,不是全局函数。imgui.window(...)返回的是 builder,不是最终窗口对象快照。- 大多数对象都在
JavaScriptBridge.register()里统一注入。
全局名速查表
| 名字 | 类型 | 是否可能为空 / 动态变化 | 最适合先看哪里 |
|---|---|---|---|
this | 宿主对象 | 否 | 本页 |
lpparam | 运行时上下文对象 | 否 | 本页 |
classLoader | ClassLoader | 否 | 本页 |
suparam | 启动参数对象 | 视场景而定 | 本页 |
context | Context | 可能拿不到 | 本页 |
activity | Activity | 更容易拿不到 | 本页 |
console | 日志对象 | 否 | 本页 |
app | 模块对象 | 否 | app 应用能力 |
files | 模块对象 | 否 | files 文件系统 |
storages | 模块对象 | 否 | storages 持久化存储 |
device | 模块对象 | 否 | device 设备能力 |
plugins | 模块对象 | 否 | 本页 |
imgui | 模块对象 | 否 | imgui 运行时面板 |
http | 模块对象 | 否 | http HTTP 客户端 |
httpServer | 模块对象 | 否 | httpServer HTTP 服务 |
mcpServer | 模块对象 | 否 | mcpServer MCP 服务 |
XpHelper / XposedHelpers / XposedBridge | 桥接对象 | 否 | 本页 |
showGlobalDialog / showHostDialog / confirm | 全局函数入口 | 否 | 本页 |
this
当前运行时里,this 不是浏览器那种 window 概念,而是“当前脚本宿主对象”。
最常见用途
- 访问被注入进去的一些宿主方法
- 显式调用全局
new(),避免和 JS 关键字冲突
const FileClass = findClass("java.io.File", lpparam.classLoader);
const file = this["new"](FileClass, "/sdcard/Download/demo.txt");
要点
- 不建议把它当成普通全局状态对象乱塞自定义字段。
- 最常见还是作为“反射辅助调用入口”。
- 如果第一参数是字符串类名,还可以写成
this["new"]("java.io.File", classLoader, ...args)显式指定查类 loader。 - 但如果第一参数已经是
Class或类代理,第二个位置就不再是特殊 loader,而会继续当构造器参数。
lpparam
lpparam 是 Xposed 包注入时最重要的上下文之一。
当前源码里明确有这些字段
| 字段 | 类型 | 说明 |
|---|---|---|
lpparam.packageName | string | 当前目标包名 |
lpparam.classLoader | ClassLoader | 当前目标默认类加载器 |
lpparam.appInfo | ApplicationInfo | Android 应用信息对象 |
lpparam.isFirstApplication | boolean | 是否首次 Application 入口 |
lpparam.processName | string | 当前目标进程名 |
最常见写法
log(`pkg=${lpparam.packageName}`);
log(`proc=${lpparam.processName}`);
const loader = lpparam.classLoader;
字段怎么理解
packageName
- 最稳定的应用标识。
- 做条件判断时,通常优先看它。
processName
- 适合区分主进程、推送进程、工具进程。
- 很多 Hook 为什么“只在某个进程生效”,就是因为这个值不同。
classLoader
- 大多数
findClass()、hook()、imports()都最终会围绕它工作。
appInfo
- 是 Android 原生
ApplicationInfo。 - 需要更底层安装信息、路径信息时很有用。
isFirstApplication
- 常用于避免某些初始化逻辑在重复入口里跑多次。
classLoader
当前脚本默认暴露出来的目标 ClassLoader,基本等价于:
lpparam.classLoader
什么时候直接用它
findClass("com.example.Target", classLoader)hook({ classloader: classLoader, ... })imports("com.example.Target")之外还想手动控类加载器时
const TargetClass = findClass("com.example.target.ProfileManager", classLoader);
suparam
这是启动参数相关上下文。
怎么理解
- 它会被运行时注入出来。
- 但对普通 App Hook 脚本来说,不一定是最高频对象。
- 更适合模块启动、Zygote、特殊初始化链路场景。
如果你的脚本主要就是日常应用 Hook,先把注意力放在:
lpparamclassLoadercontextactivity
上面通常更划算。
context
context 是动态全局对象。它不是“固定某个对象”,而是运行时按一串来源尽量帮你解析一个当前可用的 Context。
当前源码的大致解析顺序
- 当前宿主
Context - 当前对话框宿主
Activity - Application Context
XpHelper.contextActivityThread里拿到的上下文- 必要时系统
Context
这意味着什么
- 大多数时候它都能拿到
- 但你不能假设它“任何时刻绝对存在”
典型用法
if (context) {
log(String(context));
}
最适合什么时候用
- 拿系统服务
- 调 Android API
- 需要给 Java 侧方法传
Context
activity
activity 也是动态全局对象,但它比 context 更容易拿不到。
当前源码的大致来源
- 当前宿主如果本身就是
Activity - 当前对话框宿主
Activity XpHelper.context能否还原成Activity- 当前
context能否再解成Activity
什么时候容易是 null
- 后台脚本
- 服务态脚本
- 纯进程注入但当前没有可用前台页面
- 某些系统进程或无界面上下文
推荐写法
if (activity) {
toastLog(`activity=${activity}`);
}
一句话区别
context更像“尽量给你一个可用上下文”activity更像“只有真能找到页面宿主时才给你”
console
console 是为了让脚本书写更接近 Web / Node 的习惯。
当前支持的方法
| 方法 | 典型签名 | 日志级别前缀 |
|---|---|---|
console.log | console.log(...args) | 普通日志 |
console.info | console.info(...args) | INFO |
console.warn | console.warn(...args) | WARN |
console.error | console.error(...args) | ERROR |
参数规则
- 都支持多个参数。
- 都会先转字符串再用空格拼接。
- 返回值都是
null。
console.log("hello");
console.info("boot");
console.warn("watch out");
console.error("failed");
和 log() 的区别
log()是全局函数console.log()是对象方法
功能相近,主要是书写习惯不同。
app
app 是应用能力对象。
这里保留什么,不重复什么
- 这页只保留“它是一个已经注入好的对象”这个层面的说明。
- 具体方法、参数、可填值、失败行为,都只放在它自己的专页。
- 这样就不在这里再抄一遍
startActivity、launch、getInstalledApps的整套规则了。
你先知道这些就够了
app负责启动 Activity、打开应用、查包名、查已安装应用、打开设置页这类“应用层动作”。- 如果你看到脚本里写的是
app.xxx(...),就直接去它的专页,不用在这页来回对照。
最直接的入口页在这里:
files
files 是文件系统能力对象。
这里不再重复列整套 files.* 方法名。你只要先记住它负责这几类事:
- 配置文件读写
- 缓存文件处理
- 项目脚本文件管理
具体到每个方法的参数、编码、路径规则,只保留在专页:
storages
storages 是轻量持久化对象。
你可以先把它理解成:
storages.create(name)先拿一个命名存储空间- 后面围绕这个实例做
get / put / remove / contains / clear
详细的默认值、undefined 行为、JSON 兼容规则,只放在专页:
device
device 是设备信息和设备控制对象。
这页不再把亮度、音量、电量、唤醒、震动这些方法重新铺一遍。
你只需要先知道:
device既有只读属性,也有主动控制类方法- 它覆盖的信息和动作很多,真正使用时直接进专页更省时间
详细参数和取值建议看:
plugins
plugins 是插件加载对象。
它主要负责三件事:
- 动态加载插件脚本能力
- 控制某个插件包的挂载与卸载
- 把插件生命周期和当前项目脚本串起来
详细规则放在:
imgui
imgui 是运行时面板 UI 对象。
你最该记住的点
imgui.window(...)返回的是链式 builder- 同一个窗口
id会复用同一份状态 builder.clear()清内容,不清状态
控件、布局、状态读写、显示模式这些详细内容都只留在专页:
http
http 是 HTTP 客户端对象。
它是脚本侧 HTTP 客户端。
这一页不再重复列 get / post / postJson / response.body.xxx() 那套方法,而只保留对象定位。
详细规则请看:
httpServer
httpServer 是脚本内置的本地 HTTP 服务对象。
你最该记住的点
- 默认监听
127.0.0.1:18765 - 路由
req.headers的 key 会变成小写 - 路由返回对象里真实识别的状态字段是
status
完整的路由注册、返回值、认证规则只保留在:
mcpServer
mcpServer 是脚本侧 MCP 服务对象。
你最该记住的点
- 默认地址是
http://127.0.0.1:5698/mcp start()里当前认的是name/versionallowedOrigins决定非本机网页来源能不能跨域访问
Tool / Resource / Prompt 的完整方法说明只保留在:
XpHelper / XposedHelpers / XposedBridge
这几个是直接暴露出来的底层桥接对象:
XpHelperXposedHelpersXposedBridge- 另外还有
DexFinder - 以及
DexKitBridge
适合什么时候直接用它们
- JSXHook 包装 API 不够用
- 你已经很熟 Xposed 原生写法
- 你要处理更底层、更特殊的 Hook 逻辑
对新手来说,优先从:
hook(...)findClass(...)appfileshttp
这些更高层入口开始,通常会更顺。
如果你准备实际用:
DexFinderDexKitBridgeopenDexKit(...)openDexKitByClassLoader(...)
直接看 DexKit 静态检索 会更快,因为那一页已经把入口差异、枚举值、匹配器和结果对象都拆开讲了。
showGlobalDialog / showHostDialog / confirm
这 3 个其实是同一套对话框入口的别名。
源码里:
showHostDialog === showGlobalDialogconfirm === showGlobalDialog
这里不再重复放字段总表和完整示例,避免和全局函数页出现双份内容。
如果你准备实际调用它们,直接看:
这些对象从哪里来
大多数对象都在 JavaScriptBridge.register() 里统一注入。
源码里明确放进去的典型对象包括:
thissuparamlpparamclassLoader- 动态的
context - 动态的
activity consoleappfilesdevicepluginsstoragesimguihttphttpServermcpServer
另外还会暴露一些底层桥接对象:
XpHelperDexFinderXposedHelpersXposedBridgeDexKitBridge
也就是说,后面你要扩 API、查注入来源、确认对象名,最该先看的位置就是这块注册逻辑。
