diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md index 2b3432d1..b9b8cbf9 100644 --- a/docs/api/public/PackageParam.md +++ b/docs/api/public/PackageParam.md @@ -436,7 +436,7 @@ fun loadHooker(hooker: YukiBaseHooker) `v1.0.93` `作废` -请转移到 `toAppClass()` 方法 +请转移到 `toClass(...)` 方法 ### ~~String.hasClass *- i-ext-field*~~ @@ -448,14 +448,14 @@ fun loadHooker(hooker: YukiBaseHooker) 请转移到 `hasClass(...)` 方法 -### String+VariousClass.toAppClass *- i-ext-method* +### String+VariousClass.toClass *- i-ext-method* ```kotlin -fun String.toAppClass(): Class<*> +fun String.toClass(loader: ClassLoader?): Class<*> ``` ```kotlin -fun VariousClass.toAppClass(): Class<*> +fun VariousClass.toClass(loader: ClassLoader?): Class<*> ``` **变更记录** @@ -464,9 +464,9 @@ fun VariousClass.toAppClass(): Class<*> **功能描述** -> 通过字符串类名、`VariousClass` 转换为当前 Hook APP 的实体类。 +> 通过字符串类名、`VariousClass` 转换为 `loader` 中的实体类。 -使用当前 `appClassLoader` 装载目标 `Class`。 +默认使用当前 `appClassLoader` 装载目标 `Class`。 **功能示例** @@ -475,7 +475,16 @@ fun VariousClass.toAppClass(): Class<*> > 示例如下 ```kotlin -"com.example.demo.DemoClass".toAppClass() +"com.example.demo.DemoClass".toClass() +``` + +你还可以向 `loader` 参数传入你自定义的 `ClassLoader`。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +"com.example.demo.DemoClass".toClass(customClassLoader) ``` 你还可以创建一个 `VariousClass`,并转换为实体类。 @@ -485,7 +494,16 @@ fun VariousClass.toAppClass(): Class<*> > 示例如下 ```kotlin -VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toAppClass() +VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass() +``` + +同样地,你还可以向 `loader` 参数传入你自定义的 `ClassLoader`。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass(customClassLoader) ``` ### String.hasClass *- i-ext-method* @@ -502,6 +520,8 @@ fun String.hasClass(loader: ClassLoader?): Boolean > 通过字符串类名查找是否存在。 +默认使用当前 `appClassLoader` 装载目标 `Class`。 + **功能示例** 你可以轻松的使用此方法判断字符串中的类是否存在。 @@ -551,7 +571,7 @@ fun findClass(vararg name: String, loader: ClassLoader?): VariousClass > 通过完整包名+名称查找需要被 Hook 的 `Class`。 -!> 使用此方法会得到一个 `HookClass` 仅用于 Hook,若想查找 `Class` 请使用 `toClass`、`toAppClass` 功能。 +!> 使用此方法会得到一个 `HookClass` 仅用于 Hook,若想查找 `Class` 请使用 `toClass` 功能。 **功能示例** diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/reflex/tools/ReflectionTool.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/reflex/tools/ReflectionTool.kt index d9e8abea..33dee73c 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/reflex/tools/ReflectionTool.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/reflex/tools/ReflectionTool.kt @@ -33,6 +33,9 @@ import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData import com.highcapable.yukihookapi.hook.factory.hasExtends import com.highcapable.yukihookapi.hook.store.ReflectsCacheStore import com.highcapable.yukihookapi.hook.type.defined.UndefinedType +import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge +import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper +import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Member @@ -40,13 +43,43 @@ import java.lang.reflect.Method import kotlin.math.abs /** - * 这是一个对 [Member] 查找的工具实现类 + * 这是一个对 [Class]、[Member] 查找的工具实现类 */ internal object ReflectionTool { /** 当前工具类的标签 */ private const val TAG = "YukiHookAPI#ReflectionTool" + /** + * 使用字符串类名查询 [Class] 是否存在 + * @param name [Class] 完整名称 + * @param loader [Class] 所在的 [ClassLoader] + * @return [Boolean] + */ + internal fun hasClassByName(name: String, loader: ClassLoader?) = runCatching { findClassByName(name, loader); true }.getOrNull() ?: false + + /** + * 使用字符串类名获取 [Class] + * @param name [Class] 完整名称 + * @param loader [Class] 所在的 [ClassLoader] + * @return [Class] + * @throws NoClassDefFoundError 如果找不到 [Class] 或设置了错误的 [ClassLoader] + */ + internal fun findClassByName(name: String, loader: ClassLoader?): Class<*> { + val hashCode = ("[$name][$loader]").hashCode() + return ReflectsCacheStore.findClass(hashCode) ?: runCatching { + when { + YukiHookBridge.hasXposedBridge -> runCatching { YukiHookHelper.findClass(name, loader) } + .getOrNull() ?: (if (loader == null) Class.forName(name) else loader.loadClass(name)) + loader == null -> Class.forName(name) + else -> loader.loadClass(name) + }.also { ReflectsCacheStore.putClass(hashCode, it) } + }.getOrNull() ?: throw NoClassDefFoundError( + "Can't find this Class --> " + + "name:[$name] in [${loader ?: AppParasitics.baseClassLoader}] by $TAG" + ) + } + /** * 查找任意变量或一组变量 * @param classSet 变量所在类 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 7d2b63cc..3380cdf0 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 @@ -35,9 +35,7 @@ import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder import com.highcapable.yukihookapi.hook.core.finder.members.FieldFinder import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules -import com.highcapable.yukihookapi.hook.store.ReflectsCacheStore -import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge -import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper +import com.highcapable.yukihookapi.hook.core.reflex.tools.ReflectionTool import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus import java.lang.reflect.Constructor import java.lang.reflect.Field @@ -91,17 +89,7 @@ fun classOf(name: String, loader: ClassLoader? = null) = name.toClass(loader) * @return [Class] * @throws NoClassDefFoundError 如果找不到 [Class] 或设置了错误的 [ClassLoader] */ -fun String.toClass(loader: ClassLoader? = null): Class<*> { - val hashCode = ("[$this][$loader]").hashCode() - return ReflectsCacheStore.findClass(hashCode) ?: run { - when { - YukiHookBridge.hasXposedBridge -> runCatching { YukiHookHelper.findClass(name = this, loader) }.getOrNull() - ?: (if (loader == null) Class.forName(this) else loader.loadClass(this)) - loader == null -> Class.forName(this) - else -> loader.loadClass(this) - }.also { ReflectsCacheStore.putClass(hashCode, it) } - } -} +fun String.toClass(loader: ClassLoader? = null) = ReflectionTool.findClassByName(name = this, loader) /** * 通过 [T] 得到其 [Class] 实例并转换为实体类 @@ -116,7 +104,7 @@ inline fun classOf(loader: ClassLoader? = null) = loader?.let { T::c * @param loader [Class] 所在的 [ClassLoader] - 不填使用默认 [ClassLoader] * @return [Boolean] 是否存在 */ -fun String.hasClass(loader: ClassLoader? = null) = runCatching { toClass(loader); true }.getOrNull() ?: false +fun String.hasClass(loader: ClassLoader? = null) = ReflectionTool.hasClassByName(name = this, loader) /** * 查找变量是否存在 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 4db6f176..52c66d98 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 @@ -42,9 +42,8 @@ import com.highcapable.yukihookapi.hook.bean.HookResources import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator import com.highcapable.yukihookapi.hook.core.YukiResourcesHookCreator +import com.highcapable.yukihookapi.hook.core.reflex.tools.ReflectionTool import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker -import com.highcapable.yukihookapi.hook.factory.classOf -import com.highcapable.yukihookapi.hook.factory.toClass import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper import com.highcapable.yukihookapi.hook.utils.value @@ -300,26 +299,26 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: * * - ❗此方法已弃用 - 在之后的版本中将直接被删除 * - * - ❗请现在转移到 [toAppClass] + * - ❗请现在转移到 [toClass] * @return [Class] * @throws NoClassDefFoundError 如果找不到 [Class] */ - @Deprecated(message = "请使用新的命名方法", ReplaceWith(expression = "toAppClass()")) + @Deprecated(message = "请使用新的命名方法", ReplaceWith(expression = "toClass()")) val String.clazz - get() = toAppClass() + get() = toClass() /** * [VariousClass] 转换为当前 Hook APP 的实体类 * * - ❗此方法已弃用 - 在之后的版本中将直接被删除 * - * - ❗请现在转移到 [toAppClass] + * - ❗请现在转移到 [toClass] * @return [Class] * @throws IllegalStateException 如果任何 [Class] 都没有匹配到 */ - @Deprecated(message = "请使用新的命名方法", ReplaceWith(expression = "toAppClass()")) + @Deprecated(message = "请使用新的命名方法", ReplaceWith(expression = "toClass()")) val VariousClass.clazz - get() = toAppClass() + get() = toClass() /** * 通过字符串类名查找是否存在 @@ -334,36 +333,32 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: get() = hasClass() /** - * 通过字符串类名转换为当前 Hook APP 的实体类 - * - * - 使用当前 [appClassLoader] 装载目标 [Class] - * - * - 若要使用指定的 [ClassLoader] 装载 - 请手动调用 [classOf] 方法 + * 通过字符串类名转换为 [loader] 中的实体类 + * @param loader [Class] 所在的 [ClassLoader] - 不填使用 [appClassLoader] * @return [Class] * @throws NoClassDefFoundError 如果找不到 [Class] */ - fun String.toAppClass() = toClass(appClassLoader) + fun String.toClass(loader: ClassLoader? = appClassLoader) = ReflectionTool.findClassByName(name = this, loader) /** - * [VariousClass] 转换为当前 Hook APP 的实体类 - * - * - 使用当前 [appClassLoader] 装载目标 [Class] + * [VariousClass] 转换为 [loader] 中的实体类 + * @param loader [Class] 所在的 [ClassLoader] - 不填使用 [appClassLoader] * @return [Class] * @throws IllegalStateException 如果任何 [Class] 都没有匹配到 */ - fun VariousClass.toAppClass() = get(appClassLoader) + fun VariousClass.toClass(loader: ClassLoader? = appClassLoader) = get(loader) /** * 通过字符串类名查找是否存在 * @param loader [Class] 所在的 [ClassLoader] - 不填使用 [appClassLoader] * @return [Boolean] 是否存在 */ - fun String.hasClass(loader: ClassLoader? = appClassLoader) = runCatching { toClass(loader); true }.getOrNull() ?: false + fun String.hasClass(loader: ClassLoader? = appClassLoader) = ReflectionTool.hasClassByName(name = this, loader) /** * 查找并装载 [HookClass] * - * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [toClass]、[toAppClass] 功能 + * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [toClass] 功能 * @param name 类名 * @param loader 当前 [ClassLoader] - 默认使用 [appClassLoader] - 设为 null 使用默认 [ClassLoader] * @return [HookClass] @@ -376,7 +371,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: * * 使用此方法查找将会取 [name] 其中命中存在的第一个 [Class] 作为结果 * - * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [toClass]、[toAppClass] 功能 + * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [toClass] 功能 * @param name 可填入多个类名 - 自动匹配 * @param loader 当前 [ClassLoader] - 默认使用 [appClassLoader] - 设为 null 使用默认 [ClassLoader] * @return [HookClass]