EzHookTool API Guide
EzHookTool 的 API 分成三类:
-
core:反射、类查找、方法查找、字段读写、实例创建。 -
core.java:给 Java 调用的入口,例如Classes、Methods、Fields、Constructors。 -
xposed.dsl/xposed.java:给 Kotlin / Java 使用的 hook 入口。
本项目不做 dex 扫描。类查找只处理已知类名或候选类名;成员查找只在给定 Class 的成员和父类成员中查找。
Kotlin
查找单个方法:
val method = clazz.findMethod {
name("foo")
paramCount(2)
returnType(String::class.java)
}
查找多个方法:
val methods = clazz.findAllMethods {
name("foo")
paramCount(2)
includeSuper()
}
不写条件时会返回当前查找范围内的全部结果:
val methods = clazz.findAllMethods()
val declaredFields = clazz.findAllFields {
currentClassOnly()
}
常用方法条件:
val method = clazz.findMethod {
nameContains("open")
paramCountIn(1..3)
paramsAssignableFrom(String::class.java)
returnTypeExtendsFrom(CharSequence::class.java)
isPublic()
notStatic()
}
查找字段:
val field = clazz.findField {
name("mContext")
type(Context::class.java)
currentClassOnly()
}
查找构造器:
val constructor = clazz.findConstructor {
noParams()
isPublic()
}
安装 hook:
method.createHook {
before {
val text = argAs<String>(0)
args[0] = text.trim()
}
after {
result = "done"
}
}
批量 hook:
clazz.findAllMethods {
name("foo")
paramCount(1)
}.createHooks {
before {
// ...
}
}
Java
Java 代码建议使用 core.java 包里的入口。链式查询方法使用 filterBy... 命名,能直接看出每一步是在追加查找条件。
查找类:
import io.github.lingqiqi5211.ezhooktool.core.java.Classes;
Class<?> target = Classes.findClass("com.example.Target");
多个候选类名按顺序兜底:
Class<?> target = Classes.findFirstClass(
"com.example.Target",
"com.example.a"
);
查找方法:
import io.github.lingqiqi5211.ezhooktool.core.java.Methods;
Method method = Methods.find(target)
.filterByName("foo")
.filterByParamCount(2)
.filterByReturnType(String.class)
.includeSuper()
.first();
更宽松的参数匹配:
Method method = Methods.find(target)
.filterByNameContains("open")
.filterByAssignableParamTypes(String.class)
.filterByReturnTypeExtendsFrom(CharSequence.class)
.filterPublic()
.first();
查找字段:
import io.github.lingqiqi5211.ezhooktool.core.java.Fields;
Field field = Fields.find(target)
.filterByName("mContext")
.filterByType(Context.class)
.currentClassOnly()
.first();
查找构造器:
import io.github.lingqiqi5211.ezhooktool.core.java.Constructors;
Constructor<?> constructor = Constructors.find(target)
.filterEmptyParam()
.filterPublic()
.first();
安装 before / after hook:
import io.github.lingqiqi5211.ezhooktool.xposed.common.HookParam;
import io.github.lingqiqi5211.ezhooktool.xposed.java.Hooks;
import io.github.lingqiqi5211.ezhooktool.xposed.java.IMethodHook;
Hooks.createHook(method, new IMethodHook() {
@Override
public void before(HookParam param) {
Object[] args = param.getArgs();
args[0] = ((String) args[0]).trim();
}
@Override
public void after(HookParam param) {
param.setResult("done");
}
});
安装 replace hook:
import io.github.lingqiqi5211.ezhooktool.xposed.java.IReplaceHook;
Hooks.createHook(method, new IReplaceHook() {
@Override
public Object replace(HookParam param) {
return null;
}
});
查找并 hook 单个方法:
Hooks.findAndHookMethod(target, "foo", String.class, new IMethodHook() {
@Override
public void before(HookParam param) {
// ...
}
});
批量 hook:
List<Method> methods = Methods.find(target)
.filterByName("foo")
.filterByParamCount(1)
.toList();
Hooks.createHooks(methods, new IMethodHook() {
@Override
public void before(HookParam param) {
// ...
}
});
查找范围
方法和字段默认使用智能查找:先查当前类,找不到再查父类。
-
currentClassOnly():只查当前类。 -
includeSuper():查当前类和全部父类。
不写这两个开关时,就是默认智能查找。
也可以在函数参数里直接指定:
clazz.findMethod(findSuper = false) {
name("foo")
}
查询条件
方法查询常用条件:
-
name("foo")/nameContains("foo")/nameStartsWith("get")/nameEndsWith("Locked") -
paramCount(2)/paramCountIn(1..3)/noParams()/hasParams() -
params(String::class.java):完整参数类型,数量和顺序必须一致。 -
paramsAssignableFrom(String::class.java):目标方法参数能接收这些类型。 -
returnType(String::class.java)/returnTypeExtendsFrom(CharSequence::class.java)/voidReturnType() -
isStatic()/notStatic()/isPublic()/isPrivate()/isProtected() -
isFinal()/isAbstract()/isNative()/isSynchronized() -
isVarArgs()/isSynthetic()/isBridge()/isDefault() -
filter { ... }:自定义条件。
字段查询常用条件:
-
name("mContext")/nameContains("context") -
type(Context::class.java)/typeExtendsFrom(Context::class.java) -
isStatic()/notStatic() -
isPublic()/isPrivate()/isProtected() -
isFinal()/isVolatile()/isTransient() -
isEnumConstant()/isSynthetic() -
filter { ... }:自定义条件。
构造器查询常用条件:
-
paramCount(2)/paramCountIn(1..3)/noParams()/hasParams() -
params(String::class.java):完整参数类型,数量和顺序必须一致。 -
paramsAssignableFrom(String::class.java):目标构造器参数能接收这些类型。 -
isPublic()/isPrivate()/isProtected() -
isVarArgs()/isSynthetic() -
filter { ... }:自定义条件。
Java 入口使用同义的 filterBy...、filterPublic()、filterStatic() 等方法。
查询缓存
缓存保存的是最终查找结果,不保存查找过程。
会缓存的结果:
-
findClass/findClassOrNull:按ClassLoader + 类名缓存成功加载的类。 -
findFirstClass/findFirstClassOrNull:按ClassLoader + 候选类名列表缓存第一个成功结果。 -
findMethod/findField/findConstructor:按结构化查询条件缓存第一个匹配结果。 -
best-match 查找:按名称和参数类型缓存匹配结果。
不会缓存的内容:
-
找不到的类或成员。
-
findAllMethods/findAllFields/findAllConstructors的列表本身。 -
自定义
filter { ... }的结果。
findAll 的行为:
-
带查询条件的
findAll会先走一次对应的单个查找,让单个查找缓存先命中或预热。 -
随后再查出完整列表。
-
列表里的每个结果会按精确签名写入单个查找缓存。
缓存只保存在当前运行期内。高频命中的缓存会刷新访问记录;低频缓存会在内部清理条件达成后自动释放。
关闭缓存会释放已有缓存,也可以手动清除:
EzReflect.cacheEnabled = false
EzReflect.clearCache()
init()、reset() 和 clearCache() 都会清空缓存。
调用和字段读写
Kotlin:
val value = obj.callMethod("getValue")
obj.putField("enabled", true)
Java:
Object value = Methods.callMethod(obj, "getValue");
Fields.setBooleanField(obj, "enabled", true);
libxposed 101 intercept
intercept 只用于需要直接操作 XposedInterface.Chain 的场景。
Hooks.intercept(method, chain -> {
Object[] args = chain.getArgs().toArray();
return chain.proceed(args);
});