mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
Added DexClassFinder function allowed ClassLoader to search classes (Beta Feature)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/4.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.core.finder.base
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerI
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
||||
|
||||
/**
|
||||
* 这是 [Class] 查找类功能的基本类实现
|
||||
* @param loaderSet 当前使用的 [ClassLoader] 实例
|
||||
*/
|
||||
abstract class ClassBaseFinder internal constructor(internal open val loaderSet: ClassLoader? = null) : BaseFinder() {
|
||||
|
||||
/** 当前找到的 [Class] 数组 */
|
||||
internal var classInstances = HashSet<Class<*>>()
|
||||
|
||||
/** 是否开启忽略错误警告功能 */
|
||||
internal var isShutErrorPrinting = false
|
||||
|
||||
/**
|
||||
* 将目标类型转换为可识别的兼容类型
|
||||
* @param any 当前需要转换的实例
|
||||
* @param tag 当前查找类的标识
|
||||
* @return [Class] or null
|
||||
*/
|
||||
internal fun compatType(any: Any?, tag: String) = any?.compat(tag, loaderSet)
|
||||
|
||||
/**
|
||||
* 在开启 [YukiHookAPI.Configs.isDebug] 且在 [YukiHookBridge.hasXposedBridge] 情况下输出调试信息
|
||||
* @param msg 调试日志内容
|
||||
*/
|
||||
internal fun onDebuggingMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug && YukiHookBridge.hasXposedBridge) yLoggerI(msg = msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误时输出日志
|
||||
* @param throwable 错误
|
||||
*/
|
||||
internal fun onFailureMsg(throwable: Throwable? = null) {
|
||||
if (isShutErrorPrinting) return
|
||||
yLoggerE(msg = "NoClassDefFound happend in [$loaderSet]", e = throwable)
|
||||
}
|
||||
|
||||
@YukiPrivateApi
|
||||
override fun failure(throwable: Throwable?) = error("DexClassFinder does not contain this usage")
|
||||
}
|
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/4.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.SystemClock
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.ClassBaseFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.data.ClassRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.ConstructorRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.FieldRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.MemberRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.MethodRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.base.BaseRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.result.MemberRulesResult
|
||||
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.searchClass
|
||||
import com.highcapable.yukihookapi.hook.factory.toClass
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.utils.await
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
|
||||
import dalvik.system.BaseDexClassLoader
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* [Class] 查找类
|
||||
*
|
||||
* 可使用 [BaseDexClassLoader] 通过指定条件查找指定 [Class] 或一组 [Class]
|
||||
*
|
||||
* - ❗此功能尚在试验阶段 - 性能与稳定性可能仍然存在问题 - 使用过程遇到问题请向我们报告并帮助我们改进
|
||||
* @param name 标识当前 [Class] 缓存的名称 - 不设置将不启用缓存 - 启用缓存必须启用 [async]
|
||||
* @param async 是否启用异步
|
||||
* @param loaderSet 当前使用的 [ClassLoader] 实例
|
||||
*/
|
||||
class DexClassFinder @PublishedApi internal constructor(
|
||||
internal var name: String,
|
||||
internal var async: Boolean,
|
||||
override val loaderSet: ClassLoader?
|
||||
) : ClassBaseFinder(loaderSet) {
|
||||
|
||||
companion object {
|
||||
|
||||
/** 缓存的存储文件名 */
|
||||
private const val CACHE_FILE_NAME = "config_yukihook_cache_obfuscate_classes"
|
||||
|
||||
/**
|
||||
* 通过 [Context] 获取当前 [SharedPreferences]
|
||||
* @param versionName 版本名称 - 默认空
|
||||
* @param versionCode 版本号 - 默认空
|
||||
* @return [SharedPreferences]
|
||||
*/
|
||||
private fun Context.currentSp(versionName: String? = null, versionCode: Long? = null) =
|
||||
getSharedPreferences(packageManager?.getPackageInfo(packageName, PackageManager.GET_META_DATA)
|
||||
?.let { "${CACHE_FILE_NAME}_${versionName ?: it.versionName}_${versionCode ?: PackageInfoCompat.getLongVersionCode(it)}" }
|
||||
?: "${CACHE_FILE_NAME}_unknown",
|
||||
Context.MODE_PRIVATE)
|
||||
|
||||
/**
|
||||
* 清除当前 [DexClassFinder] 的 [Class] 缓存
|
||||
*
|
||||
* 适用于全部通过 [ClassLoader.searchClass] or [PackageParam.searchClass] 获取的 [DexClassFinder]
|
||||
* @param context 当前 [Context] - 不填默认获取 [YukiHookAppHelper.currentApplication]
|
||||
* @param versionName 版本名称 - 默认空
|
||||
* @param versionCode 版本号 - 默认空
|
||||
*/
|
||||
fun clearCache(context: Context? = YukiHookAppHelper.currentApplication(), versionName: String? = null, versionCode: Long? = null) {
|
||||
context?.currentSp(versionName, versionCode)?.edit()?.clear()?.apply()
|
||||
?: yLoggerW(msg = "Cannot clear cache for DexClassFinder because got null context instance")
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
override var rulesData = ClassRulesData()
|
||||
|
||||
/**
|
||||
* 设置 [Class] 完整名称
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getName]
|
||||
*
|
||||
* 例如 com.demo.Test 需要填写 com.demo.Test
|
||||
* @return [String]
|
||||
*/
|
||||
var fullName
|
||||
get() = rulesData.fullName?.name ?: ""
|
||||
set(value) {
|
||||
rulesData.fullName = rulesData.createNameRulesData(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 简单名称
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getSimpleName]
|
||||
*
|
||||
* 例如 com.demo.Test 只需要填写 Test
|
||||
*
|
||||
* 对于匿名类例如 com.demo.Test$InnerTest 会为空 - 此时你可以使用 [singleName]
|
||||
* @return [String]
|
||||
*/
|
||||
var simpleName
|
||||
get() = rulesData.simpleName?.name ?: ""
|
||||
set(value) {
|
||||
rulesData.simpleName = rulesData.createNameRulesData(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 独立名称
|
||||
*
|
||||
* 设置后将首先使用 [Class.getSimpleName] - 若为空则会使用 [Class.getName] 进行处理
|
||||
*
|
||||
* 例如 com.demo.Test 只需要填写 Test
|
||||
*
|
||||
* 对于匿名类例如 com.demo.Test$InnerTest 只需要填写 Test$InnerTest
|
||||
* @return [String]
|
||||
*/
|
||||
var singleName
|
||||
get() = rulesData.singleName?.name ?: ""
|
||||
set(value) {
|
||||
rulesData.singleName = rulesData.createNameRulesData(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置在指定包名范围查询当前 [Class]
|
||||
*
|
||||
* 设置后仅会在当前 [name] 开头匹配的包名路径下进行查询 - 可提升查询速度
|
||||
*
|
||||
* 例如 ↓
|
||||
*
|
||||
* com.demo.test
|
||||
*
|
||||
* com.demo.test.demo
|
||||
*
|
||||
* - ❗建议设置此参数指定查询范围 - 否则 [Class] 过多时将会非常慢
|
||||
* @param name 指定包名
|
||||
* @return [FromPackageRules] 可设置 [FromPackageRules.absolute] 标识包名绝对匹配
|
||||
*/
|
||||
fun from(vararg name: String) = FromPackageRules(arrayListOf<ClassRulesData.PackageRulesData>().also {
|
||||
name.takeIf { e -> e.isNotEmpty() }?.forEach { e -> it.add(rulesData.createPackageRulesData(e)) }
|
||||
if (it.isNotEmpty()) rulesData.fromPackages.addAll(it)
|
||||
})
|
||||
|
||||
/**
|
||||
* 设置 [Class] 标识符筛选条件
|
||||
*
|
||||
* - 可不设置筛选条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun modifiers(conditions: ModifierConditions) {
|
||||
rulesData.modifiers = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 完整名称
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getName]
|
||||
*
|
||||
* 例如 com.demo.Test 需要填写 com.demo.Test
|
||||
* @param value 名称
|
||||
* @return [ClassNameRules] 可设置 [ClassNameRules.optional] 标识类名可选
|
||||
*/
|
||||
fun fullName(value: String) = rulesData.createNameRulesData(value).let {
|
||||
rulesData.fullName = it
|
||||
ClassNameRules(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 简单名称
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getSimpleName]
|
||||
*
|
||||
* 例如 com.demo.Test 只需要填写 Test
|
||||
*
|
||||
* 对于匿名类例如 com.demo.Test$InnerTest 会为空 - 此时你可以使用 [singleName]
|
||||
* @param value 名称
|
||||
* @return [ClassNameRules] 可设置 [ClassNameRules.optional] 标识类名可选
|
||||
*/
|
||||
fun simpleName(value: String) = rulesData.createNameRulesData(value).let {
|
||||
rulesData.simpleName = it
|
||||
ClassNameRules(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 独立名称
|
||||
*
|
||||
* 设置后将首先使用 [Class.getSimpleName] - 若为空则会使用 [Class.getName] 进行处理
|
||||
*
|
||||
* 例如 com.demo.Test 只需要填写 Test
|
||||
*
|
||||
* 对于匿名类例如 com.demo.Test$InnerTest 只需要填写 Test$InnerTest
|
||||
* @param value 名称
|
||||
* @return [ClassNameRules] 可设置 [ClassNameRules.optional] 标识类名可选
|
||||
*/
|
||||
fun singleName(value: String) = rulesData.createNameRulesData(value).let {
|
||||
rulesData.singleName = it
|
||||
ClassNameRules(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 完整名称条件
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getName]
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun fullName(conditions: NameConditions) {
|
||||
rulesData.fullNameConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 简单名称条件
|
||||
*
|
||||
* 只会查询匹配到的 [Class.getSimpleName]
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun simpleName(conditions: NameConditions) {
|
||||
rulesData.simpleNameConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 独立名称条件
|
||||
*
|
||||
* 设置后将首先使用 [Class.getSimpleName] - 若为空则会使用 [Class.getName] 进行处理
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun singleName(conditions: NameConditions) {
|
||||
rulesData.singleNameConditions = conditions
|
||||
}
|
||||
|
||||
/** 设置 [Class] 继承的父类 */
|
||||
inline fun <reified T> extends() {
|
||||
rulesData.extendsClass.add(T::class.java.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 继承的父类
|
||||
*
|
||||
* 会同时查询 [name] 中所有匹配的父类
|
||||
* @param name [Class] 完整名称
|
||||
*/
|
||||
fun extends(vararg name: String) {
|
||||
rulesData.extendsClass.addAll(name.toList())
|
||||
}
|
||||
|
||||
/** 设置 [Class] 实现的接口类 */
|
||||
inline fun <reified T> implements() {
|
||||
rulesData.implementsClass.add(T::class.java.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 实现的接口类
|
||||
*
|
||||
* 会同时查询 [name] 中所有匹配的接口类
|
||||
* @param name [Class] 完整名称
|
||||
*/
|
||||
fun implements(vararg name: String) {
|
||||
rulesData.implementsClass.addAll(name.toList())
|
||||
}
|
||||
|
||||
/**
|
||||
* 标识 [Class] 为匿名类
|
||||
*
|
||||
* 例如 com.demo.Test$1 或 com.demo.Test$InnerTest
|
||||
*
|
||||
* 标识后你可以使用 [enclosing] 来进一步指定匿名类的 (封闭类) 主类
|
||||
*/
|
||||
fun anonymous() {
|
||||
rulesData.isAnonymousClass = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 没有任何继承
|
||||
*
|
||||
* 此时 [Class] 只应该继承于 [Any]
|
||||
*
|
||||
* - ❗设置此条件后 [extends] 将失效
|
||||
*/
|
||||
fun noExtends() {
|
||||
rulesData.isNoExtendsClass = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 没有任何接口
|
||||
*
|
||||
* - ❗设置此条件后 [implements] 将失效
|
||||
*/
|
||||
fun noImplements() {
|
||||
rulesData.isNoImplementsClass = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 没有任何继承与接口
|
||||
*
|
||||
* 此时 [Class] 只应该继承于 [Any]
|
||||
*
|
||||
* - ❗设置此条件后 [extends] 与 [implements] 将失效
|
||||
*/
|
||||
fun noSuper() {
|
||||
noExtends()
|
||||
noImplements()
|
||||
}
|
||||
|
||||
/** 设置 [Class] 匿名类的 (封闭类) 主类 */
|
||||
inline fun <reified T> enclosing() {
|
||||
rulesData.enclosingClass.add(T::class.java.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 匿名类的 (封闭类) 主类
|
||||
*
|
||||
* 会同时查询 [name] 中所有匹配的 (封闭类) 主类
|
||||
* @param name [Class] 完整名称
|
||||
*/
|
||||
fun enclosing(vararg name: String) {
|
||||
rulesData.enclosingClass.addAll(name.toList())
|
||||
}
|
||||
|
||||
/**
|
||||
* 包名范围名称过滤匹配条件实现类
|
||||
* @param packages 包名数组
|
||||
*/
|
||||
inner class FromPackageRules internal constructor(private val packages: ArrayList<ClassRulesData.PackageRulesData>) {
|
||||
|
||||
/**
|
||||
* 设置包名绝对匹配
|
||||
*
|
||||
* 例如有如下包名 ↓
|
||||
*
|
||||
* com.demo.test.a
|
||||
*
|
||||
* com.demo.test.a.b
|
||||
*
|
||||
* com.demo.test.active
|
||||
*
|
||||
* 若包名条件为 "com.demo.test.a" 则绝对匹配仅能匹配到第一个
|
||||
*
|
||||
* 相反地 - 不设置以上示例会全部匹配
|
||||
*/
|
||||
fun absolute() = packages.takeIf { it.isNotEmpty() }?.forEach { it.isAbsolute = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* 类名匹配条件实现类
|
||||
* @param name 类名匹配实例
|
||||
*/
|
||||
inner class ClassNameRules internal constructor(private val name: ClassRulesData.NameRulesData) {
|
||||
|
||||
/**
|
||||
* 设置类名可选
|
||||
*
|
||||
* 例如有如下类名 ↓
|
||||
*
|
||||
* com.demo.Test (fullName) / Test (simpleName)
|
||||
*
|
||||
* defpackage.a (fullName) / a (simpleName)
|
||||
*
|
||||
* 这两个类名都是同一个类 - 但是在有些版本中被混淆有些版本没有
|
||||
*
|
||||
* 此时可设置类名为 "com.demo.Test" (fullName) / "Test" (simpleName)
|
||||
*
|
||||
* 这样就可在完全匹配类名情况下使用类名而忽略其它查询条件 - 否则忽略此条件继续使用其它查询条件
|
||||
*/
|
||||
fun optional() {
|
||||
name.isOptional = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Class] 满足的 [Member] 条件
|
||||
* @param initiate 条件方法体
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
inline fun member(initiate: MemberRules.() -> Unit = {}) = BaseRules.createMemberRules(this).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 设置 [Class] 满足的 [Field] 条件
|
||||
* @param initiate 条件方法体
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
inline fun field(initiate: FieldRules.() -> Unit = {}) = BaseRules.createFieldRules(this).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 设置 [Class] 满足的 [Method] 条件
|
||||
* @param initiate 条件方法体
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
inline fun method(initiate: MethodRules.() -> Unit = {}) = BaseRules.createMethodRules(this).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 设置 [Class] 满足的 [Constructor] 条件
|
||||
* @param initiate 查找方法体
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
inline fun constructor(initiate: ConstructorRules.() -> Unit = {}) = BaseRules.createConstructorRules(this).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 得到 [Class] 或一组 [Class]
|
||||
* @return [HashSet]<[Class]>
|
||||
* @throws NoClassDefFoundError 如果找不到 [Class]
|
||||
*/
|
||||
private val result get() = ReflectionTool.findClasses(loaderSet, rulesData)
|
||||
|
||||
/**
|
||||
* 从本地缓存读取 [Class] 数据
|
||||
* @return [HashSet]<[Class]>
|
||||
*/
|
||||
private fun readFromCache(): HashSet<Class<*>> =
|
||||
if (async && name.isNotBlank()) YukiHookAppHelper.currentApplication()?.let {
|
||||
hashSetOf<Class<*>>().also { classes ->
|
||||
it.currentSp().getStringSet(name, emptySet())?.takeIf { it.isNotEmpty() }
|
||||
?.forEach { className -> if (className.hasClass(loaderSet)) classes.add(className.toClass(loaderSet)) }
|
||||
}
|
||||
} ?: let { SystemClock.sleep(1); readFromCache() } else hashSetOf()
|
||||
|
||||
/**
|
||||
* 将当前 [Class] 数组名称保存到本地缓存
|
||||
* @throws IllegalStateException 如果当前包名为 "android"
|
||||
*/
|
||||
private fun HashSet<Class<*>>.saveToCache() {
|
||||
if (name.isNotBlank() && isNotEmpty()) hashSetOf<String>().also { names ->
|
||||
takeIf { it.isNotEmpty() }?.forEach { names.add(it.name) }
|
||||
YukiHookAppHelper.currentApplication()?.also {
|
||||
if (it.packageName == "android") error("Cannot create classes cache for \"android\", please remove \"name\" param")
|
||||
it.currentSp().edit().apply { putStringSet(name, names) }.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实例
|
||||
* @param classes 当前找到的 [Class] 数组
|
||||
*/
|
||||
private fun setInstance(classes: HashSet<Class<*>>) {
|
||||
classInstances.clear()
|
||||
classes.takeIf { it.isNotEmpty() }?.forEach { classInstances.add(it) }
|
||||
}
|
||||
|
||||
@YukiPrivateApi
|
||||
override fun build() = runCatching {
|
||||
if (loaderSet != null) {
|
||||
/** 开始任务 */
|
||||
fun startProcess() {
|
||||
runBlocking {
|
||||
setInstance(readFromCache().takeIf { it.isNotEmpty() } ?: result)
|
||||
}.result { ms -> classInstances.takeIf { it.isNotEmpty() }?.forEach { onDebuggingMsg(msg = "Find Class [$it] takes ${ms}ms") } }
|
||||
}
|
||||
Result().also { e ->
|
||||
if (async) e.await {
|
||||
runCatching {
|
||||
startProcess()
|
||||
it.waitResultCallback?.invoke(it.get())
|
||||
it.waitAllResultCallback?.invoke(it.all())
|
||||
classInstances.saveToCache()
|
||||
}.onFailure { e ->
|
||||
it.isNotFound = true
|
||||
it.throwable = e
|
||||
it.noClassDefFoundErrorCallback?.invoke()
|
||||
onFailureMsg(throwable = e)
|
||||
}
|
||||
} else startProcess()
|
||||
}
|
||||
} else Result(isNotFound = true, Throwable("loaderSet is null")).await { onFailureMsg() }
|
||||
}.getOrElse { e -> Result(isNotFound = true, e).await { onFailureMsg(throwable = e) } }
|
||||
|
||||
/**
|
||||
* [Class] 查找结果实现类
|
||||
* @param isNotFound 是否没有找到 [Class] - 默认否
|
||||
* @param throwable 错误信息
|
||||
*/
|
||||
inner class Result internal constructor(
|
||||
@PublishedApi internal var isNotFound: Boolean = false,
|
||||
@PublishedApi internal var throwable: Throwable? = null
|
||||
) : BaseResult {
|
||||
|
||||
/** 异步方法体回调结果 */
|
||||
internal var waitResultCallback: ((Class<*>?) -> Unit)? = null
|
||||
|
||||
/** 异步方法体回调数组结果 */
|
||||
internal var waitAllResultCallback: ((HashSet<Class<*>>) -> Unit)? = null
|
||||
|
||||
/** 异常结果重新回调方法体 */
|
||||
internal var noClassDefFoundErrorCallback: (() -> Unit)? = null
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
inline fun result(initiate: Result.() -> Unit) = apply(initiate)
|
||||
|
||||
/**
|
||||
* 得到 [Class] 本身
|
||||
*
|
||||
* - 若有多个 [Class] 结果只会返回第一个
|
||||
*
|
||||
* - 在查询条件找不到任何结果的时候将返回 null
|
||||
*
|
||||
* - ❗若你设置了 [async] 请使用 [wait] 方法
|
||||
* @return [Class] or null
|
||||
*/
|
||||
fun get() = all().takeIf { it.isNotEmpty() }?.first()
|
||||
|
||||
/**
|
||||
* 得到 [Class] 本身数组
|
||||
*
|
||||
* - 返回全部查询条件匹配的多个 [Class] 实例
|
||||
*
|
||||
* - 在查询条件找不到任何结果的时候将返回空的 [HashSet]
|
||||
*
|
||||
* - ❗若你设置了 [async] 请使用 [waitAll] 方法
|
||||
* @return [HashSet]<[Class]>
|
||||
*/
|
||||
fun all() = classInstances
|
||||
|
||||
/**
|
||||
* 得到 [Class] 本身数组 (依次遍历)
|
||||
*
|
||||
* - 回调全部查询条件匹配的多个 [Class] 实例
|
||||
*
|
||||
* - 在查询条件找不到任何结果的时候将不会执行
|
||||
*
|
||||
* - ❗若你设置了 [async] 请使用 [waitAll] 方法
|
||||
* @param result 回调每个结果
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun all(result: (Class<*>) -> Unit): Result {
|
||||
all().takeIf { it.isNotEmpty() }?.forEach(result)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到 [Class] 本身 (异步)
|
||||
*
|
||||
* - 若有多个 [Class] 结果只会回调第一个
|
||||
*
|
||||
* - 在查询条件找不到任何结果的时候将回调 null
|
||||
*
|
||||
* - ❗你需要设置 [async] 后此方法才会被回调 - 否则请使用 [get] 方法
|
||||
* @param result 回调 - ([Class] or null)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun wait(result: (Class<*>?) -> Unit): Result {
|
||||
waitResultCallback = result
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到 [Class] 本身数组 (异步)
|
||||
*
|
||||
* - 回调全部查询条件匹配的多个 [Class] 实例
|
||||
*
|
||||
* - 在查询条件找不到任何结果的时候将回调空的 [HashSet]
|
||||
*
|
||||
* - ❗你需要设置 [async] 后此方法才会被回调 - 否则请使用 [all] 方法
|
||||
* @param result 回调 - ([HashSet]<[Class]>)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun waitAll(result: (HashSet<Class<*>>) -> Unit): Result {
|
||||
waitAllResultCallback = result
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听找不到 [Class] 时
|
||||
* @param result 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoClassDefFoundError(result: (Throwable) -> Unit): Result {
|
||||
noClassDefFoundErrorCallback = { if (isNotFound) result(throwable ?: Throwable("Initialization Error")) }
|
||||
noClassDefFoundErrorCallback?.invoke()
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常并停止打印任何错误日志
|
||||
*
|
||||
* - ❗此时若要监听异常结果 - 你需要手动实现 [onNoClassDefFoundError] 方法
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun ignored(): Result {
|
||||
isShutErrorPrinting = true
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/5.
|
||||
*/
|
||||
@file:Suppress("PropertyName")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.data
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.data.BaseRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.FieldRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* [Class] 规则查询数据类
|
||||
* @param fromPackages 指定包名范围名称数组
|
||||
* @param fullName 完整名称
|
||||
* @param simpleName 简单名称
|
||||
* @param singleName 独立名称
|
||||
* @param fullNameConditions 完整名称规则
|
||||
* @param simpleNameConditions 简单名称规则
|
||||
* @param singleNameConditions 独立名称规则
|
||||
* @param isAnonymousClass 匿名类
|
||||
* @param isNoExtendsClass 无继承的父类
|
||||
* @param isNoImplementsClass 无继承的实现的接口类
|
||||
* @param extendsClass 继承的父类名称数组
|
||||
* @param implementsClass 实现的接口类名称数组
|
||||
* @param enclosingClass 包含的封闭类 (主类) 名称数组
|
||||
* @param memberRules [Member] 查询条件数据数组
|
||||
* @param fieldRules [Field] 查询条件数据数组
|
||||
* @param methodRules [Method] 查询条件数据数组
|
||||
* @param constroctorRules [Constructor] 查询条件数据数组
|
||||
*/
|
||||
@PublishedApi
|
||||
internal class ClassRulesData internal constructor(
|
||||
var fromPackages: ArrayList<PackageRulesData> = arrayListOf(),
|
||||
var fullName: NameRulesData? = null,
|
||||
var simpleName: NameRulesData? = null,
|
||||
var singleName: NameRulesData? = null,
|
||||
var fullNameConditions: NameConditions? = null,
|
||||
var simpleNameConditions: NameConditions? = null,
|
||||
var singleNameConditions: NameConditions? = null,
|
||||
var isAnonymousClass: Boolean? = null,
|
||||
var isNoExtendsClass: Boolean? = null,
|
||||
var isNoImplementsClass: Boolean? = null,
|
||||
var extendsClass: ArrayList<String> = arrayListOf(),
|
||||
var implementsClass: ArrayList<String> = arrayListOf(),
|
||||
var enclosingClass: ArrayList<String> = arrayListOf(),
|
||||
var memberRules: ArrayList<MemberRulesData> = arrayListOf(),
|
||||
var fieldRules: ArrayList<FieldRulesData> = arrayListOf(),
|
||||
var methodRules: ArrayList<MethodRulesData> = arrayListOf(),
|
||||
var constroctorRules: ArrayList<ConstructorRulesData> = arrayListOf()
|
||||
) : BaseRulesData() {
|
||||
|
||||
/**
|
||||
* 创建类名匹配条件查询数据类
|
||||
* @param name 包名
|
||||
* @return [NameRulesData]
|
||||
*/
|
||||
internal fun createNameRulesData(name: String) = NameRulesData(name)
|
||||
|
||||
/**
|
||||
* 创建包名范围名称过滤匹配条件查询数据类
|
||||
* @param name 包名
|
||||
* @return [PackageRulesData]
|
||||
*/
|
||||
internal fun createPackageRulesData(name: String) = PackageRulesData(name)
|
||||
|
||||
/**
|
||||
* 获取 [Class.getSimpleName] 与 [Class.getName] 的独立名称
|
||||
* @param instance 当前 [Class] 实例
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun classSingleName(instance: Class<*>) = instance.simpleName.takeIf { it.isNotBlank() }
|
||||
?: instance.enclosingClass?.let { it.simpleName + instance.name.replace(it.name, newValue = "") } ?: ""
|
||||
|
||||
/**
|
||||
* 类名匹配条件查询数据类
|
||||
* @param name 包名
|
||||
* @param isOptional 是否可选 - 默认否
|
||||
*/
|
||||
inner class NameRulesData internal constructor(var name: String, var isOptional: Boolean = false) {
|
||||
|
||||
/** [Class.getName] */
|
||||
internal val TYPE_NAME = 0
|
||||
|
||||
/** [Class.getSimpleName] */
|
||||
internal val TYPE_SIMPLE_NAME = 1
|
||||
|
||||
/** [Class.getSimpleName] or [Class.getName] */
|
||||
internal val TYPE_SINGLE_NAME = 2
|
||||
|
||||
/**
|
||||
* 匹配当前 [Class] 实例
|
||||
* @param instance 当前 [Class] 实例
|
||||
* @param type 判断类型
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun equals(instance: Class<*>, type: Int) = when (type) {
|
||||
TYPE_NAME -> instance.name == name
|
||||
TYPE_SIMPLE_NAME -> instance.simpleName == name
|
||||
TYPE_SINGLE_NAME -> classSingleName(instance) == name
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun toString() = "$name optional($isOptional)"
|
||||
}
|
||||
|
||||
/**
|
||||
* 包名范围名称过滤匹配条件查询数据类
|
||||
* @param name 包名
|
||||
* @param isAbsolute 是否绝对匹配 - 默认否
|
||||
*/
|
||||
inner class PackageRulesData internal constructor(var name: String, var isAbsolute: Boolean = false) {
|
||||
override fun toString() = "$name absolute($isAbsolute)"
|
||||
}
|
||||
|
||||
override val templates
|
||||
get() = arrayOf(
|
||||
fromPackages.takeIf { it.isNotEmpty() }?.let { "from:$it" } ?: "",
|
||||
fullName?.let { "fullName:[$it]" } ?: "",
|
||||
simpleName?.let { "simpleName:[$it]" } ?: "",
|
||||
singleName?.let { "singleName:[$it]" } ?: "",
|
||||
fullNameConditions?.let { "fullNameConditions:[existed]" } ?: "",
|
||||
simpleNameConditions?.let { "simpleNameConditions:[existed]" } ?: "",
|
||||
singleNameConditions?.let { "singleNameConditions:[existed]" } ?: "",
|
||||
modifiers?.let { "modifiers:${ModifierRules.templates(uniqueValue)}" } ?: "",
|
||||
isAnonymousClass?.let { "isAnonymousClass:[$it]" } ?: "",
|
||||
isNoExtendsClass?.let { "isNoExtendsClass:[$it]" } ?: "",
|
||||
isNoImplementsClass?.let { "isNoImplementsClass:[$it]" } ?: "",
|
||||
extendsClass.takeIf { it.isNotEmpty() }?.let { "extendsClass:$it" } ?: "",
|
||||
implementsClass.takeIf { it.isNotEmpty() }?.let { "implementsClass:$it" } ?: "",
|
||||
enclosingClass.takeIf { it.isNotEmpty() }?.let { "enclosingClass:$it" } ?: "",
|
||||
memberRules.takeIf { it.isNotEmpty() }?.let { "memberRules:[${it.size} existed]" } ?: "",
|
||||
fieldRules.takeIf { it.isNotEmpty() }?.let { "fieldRules:[${it.size} existed]" } ?: "",
|
||||
methodRules.takeIf { it.isNotEmpty() }?.let { "methodRules:[${it.size} existed]" } ?: "",
|
||||
constroctorRules.takeIf { it.isNotEmpty() }?.let { "constroctorRules:[${it.size} existed]" } ?: ""
|
||||
)
|
||||
|
||||
override val objectName get() = "Class"
|
||||
|
||||
override val isInitialize
|
||||
get() = super.isInitialize || fromPackages.isNotEmpty() || fullName != null || simpleName != null || singleName != null ||
|
||||
fullNameConditions != null || simpleNameConditions != null || singleNameConditions != null || isAnonymousClass != null ||
|
||||
isNoExtendsClass != null || isNoImplementsClass != null || extendsClass.isNotEmpty() || enclosingClass.isNotEmpty() ||
|
||||
memberRules.isNotEmpty() || fieldRules.isNotEmpty() || methodRules.isNotEmpty() || constroctorRules.isNotEmpty()
|
||||
|
||||
override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode()
|
||||
|
||||
override fun toString() = "[$fromPackages][$fullName][$simpleName][$singleName][$fullNameConditions][$simpleNameConditions]" +
|
||||
"[$singleNameConditions][$modifiers][$isAnonymousClass][$isNoExtendsClass][$isNoImplementsClass][$extendsClass][$implementsClass]" +
|
||||
"[$enclosingClass][$memberRules][$fieldRules][$methodRules][$constroctorRules]"
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules
|
||||
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.base.BaseRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.result.MemberRulesResult
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.CountConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import java.lang.reflect.Constructor
|
||||
|
||||
/**
|
||||
* [Constructor] 查询条件实现类
|
||||
* @param rulesData 当前查询条件规则数据
|
||||
*/
|
||||
class ConstructorRules internal constructor(@PublishedApi internal val rulesData: ConstructorRulesData) : BaseRules() {
|
||||
|
||||
/**
|
||||
* 设置 [Constructor] 参数个数
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||
*
|
||||
* 若参数个数小于零则忽略并使用 [param]
|
||||
* @return [Int]
|
||||
*/
|
||||
var paramCount
|
||||
get() = rulesData.paramCount
|
||||
set(value) {
|
||||
rulesData.paramCount = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Constructor] 标识符筛选条件
|
||||
*
|
||||
* - 可不设置筛选条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun modifiers(conditions: ModifierConditions) {
|
||||
rulesData.modifiers = conditions
|
||||
}
|
||||
|
||||
/** 设置 [Constructor] 空参数、无参数 */
|
||||
fun emptyParam() {
|
||||
rulesData.paramCount = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Constructor] 参数
|
||||
*
|
||||
* 如果同时使用了 [paramCount] 则 [paramType] 的数量必须与 [paramCount] 完全匹配
|
||||
*
|
||||
* 如果 [Constructor] 中存在一些无意义又很长的类型 - 你可以使用 [VagueType] 来替代它
|
||||
*
|
||||
* 例如下面这个参数结构 ↓
|
||||
*
|
||||
* ```java
|
||||
* Foo(String var1, boolean var2, com.demo.Test var3, int var4)
|
||||
* ```
|
||||
*
|
||||
* 此时就可以简单地写作 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* param(StringType, BooleanType, VagueType, IntType)
|
||||
* ```
|
||||
*
|
||||
* - ❗无参 [Constructor] 请使用 [emptyParam] 设置查询条件
|
||||
*
|
||||
* - ❗有参 [Constructor] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||
* @param paramType 参数类型数组 - ❗只能是 [Class]、[String]、[VariousClass]
|
||||
*/
|
||||
fun param(vararg paramType: Any) {
|
||||
if (paramType.isEmpty()) error("paramTypes is empty, please use emptyParam() instead")
|
||||
rulesData.paramTypes =
|
||||
arrayListOf<Class<*>>().apply { paramType.forEach { add(it.compat(tag = "Constructor") ?: UndefinedType) } }.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Constructor] 参数个数范围
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此方法指定参数个数范围
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* paramCount(1..5)
|
||||
* ```
|
||||
* @param numRange 个数范围
|
||||
*/
|
||||
fun paramCount(numRange: IntRange) {
|
||||
rulesData.paramCountRange = numRange
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Constructor] 参数个数条件
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此方法指定参数个数条件
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* paramCount { it >= 5 || it.isZero() }
|
||||
* ```
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun paramCount(conditions: CountConditions) {
|
||||
rulesData.paramCountConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回结果实现类
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build() = MemberRulesResult(rulesData)
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules
|
||||
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.base.BaseRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.result.MemberRulesResult
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.FieldRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import java.lang.reflect.Field
|
||||
|
||||
/**
|
||||
* [Field] 查询条件实现类
|
||||
* @param rulesData 当前查询条件规则数据
|
||||
*/
|
||||
class FieldRules internal constructor(@PublishedApi internal val rulesData: FieldRulesData) : BaseRules() {
|
||||
|
||||
/**
|
||||
* 设置 [Field] 名称
|
||||
* @return [String]
|
||||
*/
|
||||
var name
|
||||
get() = rulesData.name
|
||||
set(value) {
|
||||
rulesData.name = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Field] 类型
|
||||
*
|
||||
* - ❗只能是 [Class]、[String]、[VariousClass]
|
||||
*
|
||||
* - 可不填写类型
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var type
|
||||
get() = rulesData.type
|
||||
set(value) {
|
||||
rulesData.type = value?.compat(tag = "Field")
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Field] 标识符筛选条件
|
||||
*
|
||||
* - 可不设置筛选条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun modifiers(conditions: ModifierConditions) {
|
||||
rulesData.modifiers = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Field] 名称条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun name(conditions: NameConditions) {
|
||||
rulesData.nameConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回结果实现类
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build() = MemberRulesResult(rulesData)
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.base.BaseRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.result.MemberRulesResult
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* [Member] 查询条件实现类
|
||||
* @param rulesData 当前查询条件规则数据
|
||||
*/
|
||||
class MemberRules internal constructor(@PublishedApi internal val rulesData: MemberRulesData) : BaseRules() {
|
||||
|
||||
/**
|
||||
* 设置 [Member] 标识符筛选条件
|
||||
*
|
||||
* - 可不设置筛选条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun modifiers(conditions: ModifierConditions) {
|
||||
rulesData.modifiers = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回结果实现类
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build() = MemberRulesResult(rulesData)
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules
|
||||
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.base.BaseRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.result.MemberRulesResult
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.CountConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* [Method] 查询条件实现类
|
||||
* @param rulesData 当前查询条件规则数据
|
||||
*/
|
||||
class MethodRules internal constructor(@PublishedApi internal val rulesData: MethodRulesData) : BaseRules() {
|
||||
|
||||
/**
|
||||
* 设置 [Method] 名称
|
||||
* @return [String]
|
||||
*/
|
||||
var name
|
||||
get() = rulesData.name
|
||||
set(value) {
|
||||
rulesData.name = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 参数个数
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||
*
|
||||
* 若参数个数小于零则忽略并使用 [param]
|
||||
* @return [Int]
|
||||
*/
|
||||
var paramCount
|
||||
get() = rulesData.paramCount
|
||||
set(value) {
|
||||
rulesData.paramCount = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 返回值
|
||||
*
|
||||
* - ❗只能是 [Class]、[String]、[VariousClass]
|
||||
*
|
||||
* - 可不填写返回值
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var returnType
|
||||
get() = rulesData.returnType
|
||||
set(value) {
|
||||
rulesData.returnType = value.compat(tag = "Method")
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 标识符筛选条件
|
||||
*
|
||||
* - 可不设置筛选条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun modifiers(conditions: ModifierConditions) {
|
||||
rulesData.modifiers = conditions
|
||||
}
|
||||
|
||||
/** 设置 [Method] 空参数、无参数 */
|
||||
fun emptyParam() {
|
||||
rulesData.paramCount = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 参数
|
||||
*
|
||||
* 如果同时使用了 [paramCount] 则 [paramType] 的数量必须与 [paramCount] 完全匹配
|
||||
*
|
||||
* 如果 [Method] 中存在一些无意义又很长的类型 - 你可以使用 [VagueType] 来替代它
|
||||
*
|
||||
* 例如下面这个参数结构 ↓
|
||||
*
|
||||
* ```java
|
||||
* void foo(String var1, boolean var2, com.demo.Test var3, int var4)
|
||||
* ```
|
||||
*
|
||||
* 此时就可以简单地写作 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* param(StringType, BooleanType, VagueType, IntType)
|
||||
* ```
|
||||
*
|
||||
* - ❗无参 [Method] 请使用 [emptyParam] 设置查询条件
|
||||
*
|
||||
* - ❗有参 [Method] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||
* @param paramType 参数类型数组 - ❗只能是 [Class]、[String]、[VariousClass]
|
||||
*/
|
||||
fun param(vararg paramType: Any) {
|
||||
if (paramType.isEmpty()) error("paramTypes is empty, please use emptyParam() instead")
|
||||
rulesData.paramTypes =
|
||||
arrayListOf<Class<*>>().apply { paramType.forEach { add(it.compat(tag = "Method") ?: UndefinedType) } }.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 名称条件
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun name(conditions: NameConditions) {
|
||||
rulesData.nameConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 参数个数范围
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此方法指定参数个数范围
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* paramCount(1..5)
|
||||
* ```
|
||||
* @param numRange 个数范围
|
||||
*/
|
||||
fun paramCount(numRange: IntRange) {
|
||||
rulesData.paramCountRange = numRange
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [Method] 参数个数条件
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此方法指定参数个数条件
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* paramCount { it >= 5 || it.isZero() }
|
||||
* ```
|
||||
* @param conditions 条件方法体
|
||||
*/
|
||||
fun paramCount(conditions: CountConditions) {
|
||||
rulesData.paramCountConditions = conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回结果实现类
|
||||
* @return [MemberRulesResult]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build() = MemberRulesResult(rulesData)
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules.base
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.DexClassFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.ConstructorRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.FieldRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.MemberRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.rules.MethodRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.FieldRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* [Member] 查询条件实现父类
|
||||
* @param instance 当前查找类实例
|
||||
*/
|
||||
open class BaseRules internal constructor(internal var instance: DexClassFinder? = null) {
|
||||
|
||||
@PublishedApi
|
||||
internal companion object {
|
||||
|
||||
/**
|
||||
* 创建查询条件规则数据
|
||||
* @param instance 当前查找类实例
|
||||
* @return [MemberRulesData]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun createMemberRules(instance: DexClassFinder) =
|
||||
MemberRules(MemberRulesData().apply { instance.rulesData.memberRules.add(this) }).apply { this.instance = instance }
|
||||
|
||||
/**
|
||||
* 创建查询条件规则数据
|
||||
* @return [FieldRulesData]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun createFieldRules(instance: DexClassFinder) =
|
||||
FieldRules(FieldRulesData().apply { instance.rulesData.fieldRules.add(this) }).apply { this.instance = instance }
|
||||
|
||||
/**
|
||||
* 创建查询条件规则数据
|
||||
* @return [MethodRulesData]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun createMethodRules(instance: DexClassFinder) =
|
||||
MethodRules(MethodRulesData().apply { instance.rulesData.methodRules.add(this) }).apply { this.instance = instance }
|
||||
|
||||
/**
|
||||
* 创建查询条件规则数据
|
||||
* @return [ConstructorRulesData]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun createConstructorRules(instance: DexClassFinder) =
|
||||
ConstructorRules(ConstructorRulesData().apply { instance.rulesData.constroctorRules.add(this) }).apply { this.instance = instance }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将目标类型转换为可识别的兼容类型
|
||||
* @param tag 当前查找类的标识
|
||||
* @return [Class] or null
|
||||
*/
|
||||
internal fun Any?.compat(tag: String) = instance?.compatType(any = this, tag)
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* This file is Created by fankes on 2022/9/12.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.classes.rules.result
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.CountConditions
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* 当前 [Member] 查询条件结果实现类
|
||||
* @param rulesData 当前查询条件规则数据
|
||||
*/
|
||||
class MemberRulesResult internal constructor(private val rulesData: MemberRulesData) {
|
||||
|
||||
/**
|
||||
* 设置当前 [Member] 在查询条件中个数为 0
|
||||
* @return [MemberRulesResult] 可继续向下监听
|
||||
*/
|
||||
fun none() = count(num = 0)
|
||||
|
||||
/**
|
||||
* 设置当前 [Member] 在查询条件中需要全部匹配的个数
|
||||
* @param num 个数
|
||||
* @return [MemberRulesResult] 可继续向下监听
|
||||
*/
|
||||
fun count(num: Int): MemberRulesResult {
|
||||
rulesData.matchCount = num
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前 [Member] 在查询条件中需要全部匹配的个数范围
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* count(1..5)
|
||||
* ```
|
||||
* @param numRange 个数范围
|
||||
* @return [MemberRulesResult] 可继续向下监听
|
||||
*/
|
||||
fun count(numRange: IntRange): MemberRulesResult {
|
||||
rulesData.matchCountRange = numRange
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前 [Member] 在查询条件中需要全部匹配的个数条件
|
||||
*
|
||||
* 使用示例如下 ↓
|
||||
*
|
||||
* ```kotlin
|
||||
* count { it >= 5 || it.isZero() }
|
||||
* ```
|
||||
* @param conditions 条件方法体
|
||||
* @return [MemberRulesResult] 可继续向下监听
|
||||
*/
|
||||
fun count(conditions: CountConditions): MemberRulesResult {
|
||||
rulesData.matchCountConditions = conditions
|
||||
return this
|
||||
}
|
||||
}
|
@@ -30,28 +30,34 @@
|
||||
package com.highcapable.yukihookapi.hook.core.finder.tools
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.data.BaseRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.CountRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.data.ClassRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.FieldRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData
|
||||
import com.highcapable.yukihookapi.hook.factory.hasExtends
|
||||
import com.highcapable.yukihookapi.hook.factory.*
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.store.ReflectsCacheStore
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import com.highcapable.yukihookapi.hook.type.java.DalvikBaseDexClassLoader
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoClassDefFoundErrorClass
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoSuchFieldErrorClass
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoSuchMethodErrorClass
|
||||
import com.highcapable.yukihookapi.hook.utils.conditions
|
||||
import com.highcapable.yukihookapi.hook.utils.let
|
||||
import com.highcapable.yukihookapi.hook.utils.takeIf
|
||||
import com.highcapable.yukihookapi.hook.utils.value
|
||||
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 dalvik.system.BaseDexClassLoader
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
@@ -62,6 +68,23 @@ internal object ReflectionTool {
|
||||
/** 当前工具类的标签 */
|
||||
private const val TAG = "YukiHookAPI#ReflectionTool"
|
||||
|
||||
/**
|
||||
* 写出当前 [ClassLoader] 下所有 [Class] 名称数组
|
||||
* @param loader 当前使用的 [ClassLoader]
|
||||
* @return [List]<[String]>
|
||||
* @throws IllegalStateException 如果 [loader] 不是 [BaseDexClassLoader]
|
||||
*/
|
||||
private fun findDexClassList(loader: ClassLoader?) = ReflectsCacheStore.findDexClassList(loader.hashCode())
|
||||
?: DalvikBaseDexClassLoader.field { name = "pathList" }.ignored().get(loader.value().let {
|
||||
while (it.value !is BaseDexClassLoader) {
|
||||
if (it.value?.parent != null) it.value = it.value?.parent
|
||||
else error("ClassLoader [$loader] is not a DexClassLoader")
|
||||
}; it.value ?: error("ClassLoader [$loader] load failed")
|
||||
}).current(ignored = true)?.field { name = "dexElements" }?.array<Any>()?.flatMap { element ->
|
||||
element.current(ignored = true).field { name = "dexFile" }.current(ignored = true)
|
||||
?.method { name = "entries" }?.invoke<Enumeration<String>>()?.toList().orEmpty()
|
||||
}.orEmpty().also { if (it.isNotEmpty()) ReflectsCacheStore.putDexClassList(loader.hashCode(), it) }
|
||||
|
||||
/**
|
||||
* 使用字符串类名查询 [Class] 是否存在
|
||||
* @param name [Class] 完整名称
|
||||
@@ -89,6 +112,140 @@ internal object ReflectionTool {
|
||||
}.getOrNull() ?: throw createException(loader ?: AppParasitics.baseClassLoader, name = "Class", "name:[$name]")
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找任意 [Class] 或一组 [Class]
|
||||
* @param loaderSet 类所在 [ClassLoader]
|
||||
* @param rulesData 规则查询数据
|
||||
* @return [HashSet]<[Class]>
|
||||
* @throws IllegalStateException 如果 [loaderSet] 为 null 或未设置任何条件
|
||||
* @throws NoClassDefFoundError 如果找不到 [Class]
|
||||
*/
|
||||
internal fun findClasses(loaderSet: ClassLoader?, rulesData: ClassRulesData) = rulesData.createResult {
|
||||
ReflectsCacheStore.findClasses(hashCode(loaderSet)) ?: hashSetOf<Class<*>>().also { classes ->
|
||||
/**
|
||||
* 开始查询作业
|
||||
* @param instance 当前 [Class] 实例
|
||||
*/
|
||||
fun startProcess(instance: Class<*>) {
|
||||
conditions {
|
||||
fromPackages.takeIf { it.isNotEmpty() }?.also { and(true) }
|
||||
fullName?.also { it.equals(instance, it.TYPE_NAME).also { e -> if (it.isOptional) opt(e) else and(e) } }
|
||||
simpleName?.also { it.equals(instance, it.TYPE_SIMPLE_NAME).also { e -> if (it.isOptional) opt(e) else and(e) } }
|
||||
singleName?.also { it.equals(instance, it.TYPE_SINGLE_NAME).also { e -> if (it.isOptional) opt(e) else and(e) } }
|
||||
fullNameConditions?.also { instance.name.also { n -> and(it(n.cast(), n)) } }
|
||||
simpleNameConditions?.also { instance.simpleName.also { n -> and(it(n.cast(), n)) } }
|
||||
singleNameConditions?.also { classSingleName(instance).also { n -> and(it(n.cast(), n)) } }
|
||||
modifiers?.also { and(it(instance.cast())) }
|
||||
extendsClass.takeIf { it.isNotEmpty() }?.also { and(instance.hasExtends && it.contains(instance.superclass.name)) }
|
||||
implementsClass.takeIf { it.isNotEmpty() }
|
||||
?.also { and(instance.interfaces.isNotEmpty() && instance.interfaces.any { e -> it.contains(e.name) }) }
|
||||
enclosingClass.takeIf { it.isNotEmpty() }
|
||||
?.also { and(instance.enclosingClass != null && it.contains(instance.enclosingClass.name)) }
|
||||
isAnonymousClass?.also { and(instance.isAnonymousClass && it) }
|
||||
isNoExtendsClass?.also { and(instance.hasExtends.not() && it) }
|
||||
isNoImplementsClass?.also { and(instance.interfaces.isEmpty() && it) }
|
||||
/**
|
||||
* 匹配 [MemberRulesData]
|
||||
* @param size [Member] 个数
|
||||
* @param result 回调是否匹配
|
||||
*/
|
||||
fun MemberRulesData.matchCount(size: Int, result: (Boolean) -> Unit) {
|
||||
takeIf { it.isInitializeOfMatch }?.also { rule ->
|
||||
rule.conditions {
|
||||
value.matchCount.takeIf { it >= 0 }?.also { and(it == size) }
|
||||
value.matchCountRange.takeIf { it.isEmpty().not() }?.also { and(size in it) }
|
||||
value.matchCountConditions?.also { and(it(CountRules.with(size), size)) }
|
||||
}.finally { result(true) }.without { result(false) }
|
||||
} ?: result(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型中的 [Class] 是否存在 - 即不存在 [UndefinedType]
|
||||
* @param type 类型
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun MemberRulesData.exists(vararg type: Any?): Boolean {
|
||||
if (type.isEmpty()) return true
|
||||
for (i in type.indices) if (type[i] == UndefinedType) {
|
||||
yLoggerW(msg = "$objectName type[$i] mistake, it will be ignored in current conditions")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
memberRules.takeIf { it.isNotEmpty() }?.forEach { rule ->
|
||||
instance.existMembers?.apply {
|
||||
var numberOfFound = 0
|
||||
if (rule.isInitializeOfSuper) forEach { member ->
|
||||
rule.conditions {
|
||||
value.modifiers?.also { and(it(member.cast())) }
|
||||
}.finally { numberOfFound++ }
|
||||
}.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } }
|
||||
else rule.matchCount(size) { and(it) }
|
||||
}
|
||||
}
|
||||
fieldRules.takeIf { it.isNotEmpty() }?.forEach { rule ->
|
||||
instance.existFields?.apply {
|
||||
var numberOfFound = 0
|
||||
if (rule.isInitialize) forEach { field ->
|
||||
rule.conditions {
|
||||
value.type?.also { value.exists(it) and (it == field.type) }
|
||||
value.name.takeIf { it.isNotBlank() }?.also { and(it == field.name) }
|
||||
value.modifiers?.also { and(it(field.cast())) }
|
||||
value.nameConditions?.also { field.name.also { n -> and(it(n.cast(), n)) } }
|
||||
}.finally { numberOfFound++ }
|
||||
}.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } }
|
||||
else rule.matchCount(size) { and(it) }
|
||||
}
|
||||
}
|
||||
methodRules.takeIf { it.isNotEmpty() }?.forEach { rule ->
|
||||
instance.existMethods?.apply {
|
||||
var numberOfFound = 0
|
||||
if (rule.isInitialize) forEach { method ->
|
||||
rule.conditions {
|
||||
value.name.takeIf { it.isNotBlank() }?.also { and(it == method.name) }
|
||||
value.returnType?.also { value.exists(it) and (it == method.returnType) }
|
||||
value.paramCount.takeIf { it >= 0 }?.also { and(method.parameterTypes.size == it) }
|
||||
value.paramCountRange.takeIf { it.isEmpty().not() }?.also { and(method.parameterTypes.size in it) }
|
||||
value.paramCountConditions?.also { method.parameterTypes.size.also { s -> and(it(s.cast(), s)) } }
|
||||
value.paramTypes?.also { value.exists(*it) and (paramTypesEq(it, method.parameterTypes)) }
|
||||
value.modifiers?.also { and(it(method.cast())) }
|
||||
value.nameConditions?.also { method.name.also { n -> and(it(n.cast(), n)) } }
|
||||
}.finally { numberOfFound++ }
|
||||
}.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } }
|
||||
else rule.matchCount(size) { and(it) }
|
||||
}
|
||||
}
|
||||
constroctorRules.takeIf { it.isNotEmpty() }?.forEach { rule ->
|
||||
instance.existConstructors?.apply {
|
||||
var numberOfFound = 0
|
||||
if (rule.isInitialize) forEach { constructor ->
|
||||
rule.conditions {
|
||||
value.paramCount.takeIf { it >= 0 }?.also { and(constructor.parameterTypes.size == it) }
|
||||
value.paramCountRange.takeIf { it.isEmpty().not() }?.also { and(constructor.parameterTypes.size in it) }
|
||||
value.paramCountConditions?.also { constructor.parameterTypes.size.also { s -> and(it(s.cast(), s)) } }
|
||||
value.paramTypes?.also { value.exists(*it) and (paramTypesEq(it, constructor.parameterTypes)) }
|
||||
value.modifiers?.also { and(it(constructor.cast())) }
|
||||
}.finally { numberOfFound++ }
|
||||
}.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } }
|
||||
else rule.matchCount(size) { and(it) }
|
||||
}
|
||||
}
|
||||
}.finally { classes.add(instance) }
|
||||
}
|
||||
findDexClassList(loaderSet).takeIf { it.isNotEmpty() }?.forEach { className ->
|
||||
/** 分离包名 → com.demo.Test → com.demo (获取最后一个 "." + 简单类名的长度) → 由于末位存在 "." 最后要去掉 1 个长度 */
|
||||
(if (className.contains(other = "."))
|
||||
className.substring(0, className.length - className.split(".").let { it[it.lastIndex] }.length - 1)
|
||||
else className).also { packageName ->
|
||||
if ((fromPackages.isEmpty() || fromPackages.any {
|
||||
if (it.isAbsolute) packageName == it.name else packageName.startsWith(it.name)
|
||||
}) && className.hasClass(loaderSet)
|
||||
) startProcess(className.toClass(loaderSet))
|
||||
}
|
||||
}
|
||||
}.takeIf { it.isNotEmpty() }?.also { ReflectsCacheStore.putClasses(hashCode(loaderSet), it) } ?: throwNotFoundError(loaderSet)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找任意 [Field] 或一组 [Field]
|
||||
* @param classSet [Field] 所在类
|
||||
@@ -333,6 +490,7 @@ internal object ReflectionTool {
|
||||
is FieldRulesData -> isInitialize.not()
|
||||
is MethodRulesData -> isInitialize.not()
|
||||
is ConstructorRulesData -> isInitialize.not()
|
||||
is ClassRulesData -> isInitialize.not()
|
||||
else -> true
|
||||
}.takeIf { it }?.also { error("You must set a condition when finding a $objectName") }
|
||||
return result(this)
|
||||
@@ -374,6 +532,7 @@ internal object ReflectionTool {
|
||||
is FieldRulesData -> throw createException(instanceSet, objectName, *templates)
|
||||
is MethodRulesData -> throw createException(instanceSet, objectName, *templates)
|
||||
is ConstructorRulesData -> throw createException(instanceSet, objectName, *templates)
|
||||
is ClassRulesData -> throw createException(instanceSet ?: AppParasitics.baseClassLoader, objectName, *templates)
|
||||
else -> error("Type [$this] not allowed")
|
||||
}
|
||||
|
||||
|
@@ -30,10 +30,14 @@ package com.highcapable.yukihookapi.hook.core.finder.type.factory
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.CountRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.NameRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.DexClassFinder
|
||||
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
|
||||
|
||||
/** 定义 [DexClassFinder] 方法体类型 */
|
||||
internal typealias ClassConditions = DexClassFinder.() -> Unit
|
||||
|
||||
/** 定义 [FieldFinder] 方法体类型 */
|
||||
internal typealias FieldConditions = FieldFinder.() -> Unit
|
||||
|
||||
|
@@ -33,14 +33,12 @@ import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.bean.CurrentClass
|
||||
import com.highcapable.yukihookapi.hook.bean.GenericClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.rules.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.core.finder.classes.DexClassFinder
|
||||
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.tools.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ConstructorConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.FieldConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.MethodConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.*
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
|
||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||
import java.lang.reflect.*
|
||||
@@ -59,6 +57,22 @@ enum class MembersType {
|
||||
CONSTRUCTOR
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过当前 [ClassLoader] 按指定条件查找并得到 Dex 中的 [Class]
|
||||
*
|
||||
* - ❗此方法在 [Class] 数量过多及查找条件复杂时会非常耗时
|
||||
*
|
||||
* - ❗建议启用 [async] 或设置 [name] 参数 - [name] 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率
|
||||
*
|
||||
* - ❗此功能尚在试验阶段 - 性能与稳定性可能仍然存在问题 - 使用过程遇到问题请向我们报告并帮助我们改进
|
||||
* @param name 标识当前 [Class] 缓存的名称 - 不设置将不启用缓存 - 启用缓存自动启用 [async]
|
||||
* @param async 是否启用异步 - 默认否
|
||||
* @param initiate 方法体
|
||||
* @return [DexClassFinder.Result]
|
||||
*/
|
||||
inline fun ClassLoader.searchClass(name: String = "", async: Boolean = false, initiate: ClassConditions) =
|
||||
DexClassFinder(name, async = async || name.isNotBlank(), loaderSet = this).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 监听当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法装载
|
||||
*
|
||||
|
@@ -42,7 +42,9 @@ 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.finder.classes.DexClassFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ClassConditions
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
|
||||
@@ -292,6 +294,22 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
|
||||
*/
|
||||
fun loadHooker(hooker: YukiBaseHooker) = hooker.assignInstance(packageParam = this)
|
||||
|
||||
/**
|
||||
* 通过 [appClassLoader] 按指定条件查找并得到当前 Hook APP Dex 中的 [Class]
|
||||
*
|
||||
* - ❗此方法在 [Class] 数量过多及查找条件复杂时会非常耗时
|
||||
*
|
||||
* - ❗建议启用 [async] 或设置 [name] 参数 - [name] 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率
|
||||
*
|
||||
* - ❗此功能尚在试验阶段 - 性能与稳定性可能仍然存在问题 - 使用过程遇到问题请向我们报告并帮助我们改进
|
||||
* @param name 标识当前 [Class] 缓存的名称 - 不设置将不启用缓存 - 启用缓存自动启用 [async]
|
||||
* @param async 是否启用异步 - 默认否
|
||||
* @param initiate 方法体
|
||||
* @return [DexClassFinder.Result]
|
||||
*/
|
||||
inline fun searchClass(name: String = "", async: Boolean = false, initiate: ClassConditions) =
|
||||
DexClassFinder(name, async = async || name.isNotBlank(), appClassLoader).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 通过字符串类名转换为当前 Hook APP 的实体类
|
||||
*
|
||||
|
@@ -38,13 +38,21 @@ import java.lang.reflect.Method
|
||||
*
|
||||
* 为防止 [Class]、[Member] 复用过高造成的系统 GC 问题
|
||||
*
|
||||
* 查询后的 [Class]、[Member] 在 [YukiHookAPI.Configs.isEnableMemberCache] 启用后自动进入缓存
|
||||
* 查找后的 [Class] 自动进入缓存 - 不受任何控制
|
||||
*
|
||||
* 查找后的 [Member] 在 [YukiHookAPI.Configs.isEnableMemberCache] 启用后自动进入缓存
|
||||
*/
|
||||
internal object ReflectsCacheStore {
|
||||
|
||||
/** 缓存的 [Class] */
|
||||
/** 缓存的 [Class] 列表 */
|
||||
private val dexClassListData = HashMap<Int, List<String>>()
|
||||
|
||||
/** 缓存的 [Class] 对象 */
|
||||
private val classData = HashMap<Int, Class<*>?>()
|
||||
|
||||
/** 缓存的 [Class] 数组 */
|
||||
private val classesData = HashMap<Int, HashSet<Class<*>>>()
|
||||
|
||||
/** 缓存的 [Method] 数组 */
|
||||
private val methodsData = HashMap<Int, HashSet<Method>>()
|
||||
|
||||
@@ -54,6 +62,13 @@ internal object ReflectsCacheStore {
|
||||
/** 缓存的 [Field] 数组 */
|
||||
private val fieldsData = HashMap<Int, HashSet<Field>>()
|
||||
|
||||
/**
|
||||
* 查找缓存中的 [Class] 列表
|
||||
* @param hashCode 标识符
|
||||
* @return [List]<[Class]>
|
||||
*/
|
||||
internal fun findDexClassList(hashCode: Int) = dexClassListData[hashCode]
|
||||
|
||||
/**
|
||||
* 查找缓存中的 [Class]
|
||||
* @param hashCode 标识符
|
||||
@@ -61,6 +76,13 @@ internal object ReflectsCacheStore {
|
||||
*/
|
||||
internal fun findClass(hashCode: Int) = classData[hashCode]
|
||||
|
||||
/**
|
||||
* 查找缓存中的 [Class] 数组
|
||||
* @param hashCode 标识符
|
||||
* @return [HashSet]<[Class]> or null
|
||||
*/
|
||||
internal fun findClasses(hashCode: Int) = classesData[hashCode]
|
||||
|
||||
/**
|
||||
* 查找缓存中的 [Method] 数组
|
||||
* @param hashCode 标识符
|
||||
@@ -82,16 +104,33 @@ internal object ReflectsCacheStore {
|
||||
*/
|
||||
internal fun findFields(hashCode: Int) = fieldsData[hashCode]
|
||||
|
||||
/**
|
||||
* 写入 [Class] 列表到缓存
|
||||
* @param hashCode 标识符
|
||||
* @param instance 实例
|
||||
*/
|
||||
internal fun putDexClassList(hashCode: Int, instance: List<String>) {
|
||||
dexClassListData[hashCode] = instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 [Class] 到缓存
|
||||
* @param hashCode 标识符
|
||||
* @param instance 实例
|
||||
*/
|
||||
internal fun putClass(hashCode: Int, instance: Class<*>?) {
|
||||
if (YukiHookAPI.Configs.isEnableMemberCache.not()) return
|
||||
classData[hashCode] = instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 [Class] 数组到缓存
|
||||
* @param hashCode 标识符
|
||||
* @param instance 实例
|
||||
*/
|
||||
internal fun putClasses(hashCode: Int, instance: HashSet<Class<*>>) {
|
||||
classesData[hashCode] = instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 [Method] 数组到缓存
|
||||
* @param hashCode 标识符
|
||||
|
Reference in New Issue
Block a user