diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md
index b9b8cbf9..326e402f 100644
--- a/docs/api/public/PackageParam.md
+++ b/docs/api/public/PackageParam.md
@@ -619,69 +619,6 @@ val outsideLoader: ClassLoader? = ... // 假设这就是你的 ClassLoader
findClass("com.example.demo.OutsideClass1", "com.example.demo.OutsideClass2", "com.example.demo.OutsideClass3", loader = outsideLoader)
```
-### ClassLoader.fetching *- i-ext-method*
-
-```kotlin
-fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit)
-```
-
-**变更记录**
-
-`v1.0.93` `新增`
-
-**功能描述**
-
-> 监听并 Hook 当前 `ClassLoader` 的 `ClassLoader.loadClass` 方法。
-
-!> 请注意只有当前 `ClassLoader` 有主动使用 `ClassLoader.loadClass` 事件时才能被捕获。
-
-!> 这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。
-
-**功能示例**
-
-针对一些使用特定 `ClassLoader` 装载 `Class` 的宿主应用,你可以使用此方法来监听 `Class` 加载情况。
-
-!> 为了防止发生问题,你需要**得到一个存在的 `ClassLoader` 实例**来使用此功能。
-
-比如我们使用 `appClassLoader`。
-
-> 示例如下
-
-```kotlin
-appClassLoader.fetching { clazz, resolve ->
- // 得到 clazz 即加载对象
- clazz... // 这里进行你需要的操作
- // resolve 为 loadClass 的第二位参数,可参考官方文档的说明,一般情况下用不到
- resolve // 类型为 Boolean
-}
-```
-
-或使用你得到的存在的 `ClassLoader` 实例,可以通过 Hook 获取。
-
-> 示例如下
-
-```kotlin
-val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
-customClassLoader?.fetching { clazz, resolve ->
- // ...
-}
-```
-
-在判断到这个 `Class` 被装载成功时,开始执行你的 Hook 功能。
-
-> 示例如下
-
-```kotlin
-val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
-customClassLoader?.fetching { clazz, resolve ->
- if(clazz.name == /** 你需要的 Class 名称 */) {
- clazz.hook {
- // ...
- }
- }
-}
-```
-
### String+Class+VariousClass+HookClass.hook *- i-ext-method*
```kotlin
diff --git a/docs/api/public/ReflectionFactory.md b/docs/api/public/ReflectionFactory.md
index 892eca56..8ff09c55 100644
--- a/docs/api/public/ReflectionFactory.md
+++ b/docs/api/public/ReflectionFactory.md
@@ -64,6 +64,69 @@ CONSTRUCTOR
> 全部 `Constructor`。
+### ClassLoader.onLoadClass *- ext-method*
+
+```kotlin
+fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit)
+```
+
+**变更记录**
+
+`v1.0.93` `新增`
+
+**功能描述**
+
+> 监听当前 `ClassLoader` 的 `ClassLoader.loadClass` 方法装载。
+
+!> 请注意只有当前 `ClassLoader` 有主动使用 `ClassLoader.loadClass` 事件时才能被捕获。
+
+!> 这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。
+
+!> 只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
+
+**功能示例**
+
+针对一些使用特定 `ClassLoader` 装载 `Class` 的宿主应用,你可以使用此方法来监听 `Class` 加载情况。
+
+!> 为了防止发生问题,你需要**得到一个存在的 `ClassLoader` 实例**来使用此功能。
+
+比如我们在 `PackageParam` 中使用 `appClassLoader`。
+
+> 示例如下
+
+```kotlin
+appClassLoader.onLoadClass { clazz ->
+ // 得到 clazz 即加载对象
+ clazz... // 这里进行你需要的操作
+}
+```
+
+或使用你得到的存在的 `ClassLoader` 实例,可以通过 Hook 获取。
+
+> 示例如下
+
+```kotlin
+val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ // ...
+}
+```
+
+在判断到这个 `Class` 被装载成功时,开始执行你的 Hook 功能。
+
+> 示例如下
+
+```kotlin
+val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ if(clazz.name == /** 你需要的 Class 名称 */) {
+ clazz.hook {
+ // ...
+ }
+ }
+}
+```
+
### ~~hookClass *- field*~~
**变更记录**
diff --git a/docs/api/public/YukiMemberHookCreator.md b/docs/api/public/YukiMemberHookCreator.md
index 95ebe44b..d2dd89ef 100644
--- a/docs/api/public/YukiMemberHookCreator.md
+++ b/docs/api/public/YukiMemberHookCreator.md
@@ -152,7 +152,7 @@ fun useDangerousOperation(option: String)
你还需要在整个作用域中声明注解 `CauseProblemsApi` 以消除警告。
-若你只需要 Hook `ClassLoader` 的 `loadClass` 方法,请参考 [ClassLoader.fetching](api/document?id=classloaderfetching-i-ext-method)。
+若你只需要 Hook `ClassLoader` 的 `loadClass` 方法,请参考 [ClassLoader.onLoadClass](api/document?id=classloaderonloadclass-ext-method)。
!> 若你不知道允许此功能会带来何种后果,请勿使用。
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
index d0552ea4..b9fdc60b 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
@@ -37,6 +37,7 @@ import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Member
@@ -65,6 +66,18 @@ enum class MembersType {
CONSTRUCTOR
}
+/**
+ * 监听当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法装载
+ *
+ * - ❗请注意只有当前 [ClassLoader] 有主动使用 [ClassLoader.loadClass] 事件时才能被捕获
+ *
+ * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误
+ *
+ * - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息
+ * @param result 回调 - ([Class] 实例对象)
+ */
+fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit) = AppParasitics.hookClassLoader(loader = this, result)
+
/**
* 当前 [Class] 是否有继承关系 - 父类是 [Any] 将被认为没有继承关系
* @return [Boolean]
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
index 2948691f..8294f301 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
@@ -378,16 +378,6 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
*/
fun findClass(vararg name: String, loader: ClassLoader? = appClassLoader) = VariousClass(*name).toHookClass(loader)
- /**
- * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
- *
- * - ❗请注意只有当前 [ClassLoader] 有主动使用 [ClassLoader.loadClass] 事件时才能被捕获
- *
- * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误
- * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve)
- */
- fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) = AppParasitics.hookClassLoader(loader = this, result)
-
/**
* Hook 方法、构造方法
*
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
index 6efc0d6c..5e8b8723 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
@@ -71,6 +71,12 @@ internal object AppParasitics {
/** [Activity] 代理是否已经注册 */
private var isActivityProxyRegister = false
+ /** [ClassLoader] 是否已被 Hook */
+ private var isClassLoaderHooked = false
+
+ /** [ClassLoader] 监听回调数组 */
+ private var classLoaderCallbacks = HashMap) -> Unit>()
+
/**
* 当前 Hook APP (宿主) 的全局生命周期 [Application]
*
@@ -234,16 +240,22 @@ internal object AppParasitics {
/**
* 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
* @param loader 当前 [ClassLoader]
- * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve)
+ * @param result 回调 - ([Class] 实例对象)
*/
- internal fun hookClassLoader(loader: ClassLoader?, result: (clazz: Class<*>, resolve: Boolean) -> Unit) {
+ internal fun hookClassLoader(loader: ClassLoader?, result: (Class<*>) -> Unit) {
+ if (loader == null) return
+ if (YukiHookBridge.hasXposedBridge.not()) return yLoggerW(msg = "You can only use hook ClassLoader method in Xposed Environment")
+ classLoaderCallbacks[loader.hashCode()] = result
+ if (isClassLoaderHooked) return
runCatching {
YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringType, BooleanType) }, object : YukiMemberHook() {
override fun afterHookedMember(param: Param) {
- if (param.instance?.javaClass?.name == loader?.javaClass?.name)
- (param.result as? Class<*>?)?.also { result(it, param.args?.get(1) as? Boolean ?: false) }
+ param.instance?.also { loader ->
+ (param.result as? Class<*>?)?.also { classLoaderCallbacks[loader.hashCode()]?.invoke(it) }
+ }
}
})
+ isClassLoaderHooked = true
}.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") }
}