mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
Added much functions and Merge code
This commit is contained in:
@@ -194,7 +194,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
|
||||
}
|
||||
File("$projectPath${separator}assets").also { assFile ->
|
||||
if (File("$projectPath${separator}AndroidManifest.xml").exists()) {
|
||||
if (!assFile.exists() || !assFile.isDirectory) {
|
||||
if (assFile.exists().not() || assFile.isDirectory.not()) {
|
||||
assFile.delete()
|
||||
assFile.mkdirs()
|
||||
}
|
||||
|
@@ -299,7 +299,7 @@ object YukiHookAPI {
|
||||
|
||||
/** 输出欢迎信息调试日志 */
|
||||
private fun printSplashLog() {
|
||||
if (!Configs.isDebug || !isShowSplashLogOnceTime || isModulePackageXposedEnv) return
|
||||
if (Configs.isDebug.not() || isShowSplashLogOnceTime.not() || isModulePackageXposedEnv) return
|
||||
isShowSplashLogOnceTime = false
|
||||
yLoggerI(msg = "Welcome to YukiHookAPI $API_VERSION_NAME($API_VERSION_CODE)! Using $executorName API $executorVersion")
|
||||
}
|
||||
|
@@ -100,12 +100,12 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun hook(): Result {
|
||||
if (!YukiHookAPI.hasXposedBridge) return Result()
|
||||
if (YukiHookAPI.hasXposedBridge.not()) return Result()
|
||||
if (hookMembers.isEmpty()) error("Hook Members is empty,hook aborted")
|
||||
else Thread {
|
||||
SystemClock.sleep(10)
|
||||
if (!isDisableCreaterRunHook && hookClass.instance != null) hookMembers.forEach { (_, member) -> member.hook() }
|
||||
if (!isDisableCreaterRunHook && hookClass.instance == null)
|
||||
if (isDisableCreaterRunHook.not() && hookClass.instance != null) hookMembers.forEach { (_, member) -> member.hook() }
|
||||
if (isDisableCreaterRunHook.not() && hookClass.instance == null)
|
||||
if (onHookClassNotFoundFailureCallback == null)
|
||||
yLoggerE(msg = "HookClass [${hookClass.name}] not found", e = hookClass.throwable)
|
||||
else onHookClassNotFoundFailureCallback?.invoke(hookClass.throwable ?: Throwable("[${hookClass.name}] not found"))
|
||||
@@ -360,7 +360,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun hook() {
|
||||
if (!YukiHookAPI.hasXposedBridge || isDisableMemberRunHook) return
|
||||
if (YukiHookAPI.hasXposedBridge.not() || isDisableMemberRunHook) return
|
||||
if (hookClass.instance == null) {
|
||||
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
|
@@ -35,8 +35,9 @@ package com.highcapable.yukihookapi.hook.core.finder
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Constructor
|
||||
|
||||
@@ -61,28 +62,50 @@ class ConstructorFinder(
|
||||
/** [Constructor] 参数数组 */
|
||||
private var paramTypes: Array<out Class<*>>? = null
|
||||
|
||||
/** [ModifierRules] 实例 */
|
||||
private var modifiers: ModifierRules? = null
|
||||
|
||||
/**
|
||||
* [Constructor] 参数个数
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||
*
|
||||
* 若参数个数小于零则忽略并使用 [param]
|
||||
*/
|
||||
var paramCount = -1
|
||||
|
||||
/**
|
||||
* [Constructor] 筛选条件
|
||||
*
|
||||
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Constructor]
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||
modifiers = ModifierRules().apply(initiate)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Constructor] 参数
|
||||
*
|
||||
* 如果同时使用了 [paramCount] 则 [paramTypes] 的数量必须与 [paramCount] 完全匹配
|
||||
*
|
||||
* - ❗无参 [Constructor] 不要使用此方法
|
||||
*
|
||||
* - ❗有参 [Constructor] 必须使用此方法设定参数
|
||||
* - ❗有参 [Constructor] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||
* @param paramType 参数类型数组
|
||||
*/
|
||||
fun param(vararg paramType: Class<*>) {
|
||||
if (paramType.isEmpty()) error("paramType is empty, please delete param() method")
|
||||
if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method")
|
||||
paramTypes = paramType
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到构造方法
|
||||
* @return [Constructor]
|
||||
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||
* @throws NoSuchMethodError 如果找不到构造方法
|
||||
*/
|
||||
private val result
|
||||
get() = if (paramTypes != null)
|
||||
ReflectionUtils.findConstructorExact(classSet, *paramTypes!!)
|
||||
else ReflectionUtils.findConstructorExact(classSet)
|
||||
private val result get() = ReflectionTool.findConstructor(classSet, modifiers, paramCount, paramTypes)
|
||||
|
||||
/**
|
||||
* 设置实例
|
||||
@@ -170,7 +193,7 @@ class ConstructorFinder(
|
||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
||||
}
|
||||
}
|
||||
if (!isFindSuccess) {
|
||||
if (isFindSuccess.not()) {
|
||||
onFailureMsg(
|
||||
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
||||
throwable = lastError,
|
||||
@@ -206,7 +229,7 @@ class ConstructorFinder(
|
||||
* @param isNoSuch 是否没有找到构造方法 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
|
@@ -33,8 +33,9 @@ import android.os.SystemClock
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Field
|
||||
|
||||
@@ -50,6 +51,9 @@ class FieldFinder(
|
||||
override val classSet: Class<*>? = null
|
||||
) : BaseFinder(tag = "Field", hookInstance, classSet) {
|
||||
|
||||
/** [ModifierRules] 实例 */
|
||||
private var modifiers: ModifierRules? = null
|
||||
|
||||
/**
|
||||
* [Field] 名称
|
||||
*
|
||||
@@ -64,6 +68,16 @@ class FieldFinder(
|
||||
*/
|
||||
var type: Class<*>? = null
|
||||
|
||||
/**
|
||||
* [Field] 筛选条件
|
||||
*
|
||||
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Field]
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||
modifiers = ModifierRules().apply(initiate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到变量处理结果
|
||||
*
|
||||
@@ -80,10 +94,7 @@ class FieldFinder(
|
||||
}
|
||||
else -> try {
|
||||
runBlocking {
|
||||
memberInstance =
|
||||
if (type != null)
|
||||
ReflectionUtils.findFieldIfExists(classSet, type?.name, name)
|
||||
else classSet?.getDeclaredField(name)?.apply { isAccessible = true }
|
||||
memberInstance = ReflectionTool.findField(classSet, name, modifiers, type)
|
||||
}.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") }
|
||||
Result()
|
||||
} catch (e: Throwable) {
|
||||
@@ -111,7 +122,7 @@ class FieldFinder(
|
||||
* @param isNoSuch 是否没有找到变量 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
|
@@ -35,9 +35,10 @@ package com.highcapable.yukihookapi.hook.core.finder
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Method
|
||||
|
||||
@@ -62,6 +63,9 @@ class MethodFinder(
|
||||
/** [Method] 参数数组 */
|
||||
private var paramTypes: Array<out Class<*>>? = null
|
||||
|
||||
/** [ModifierRules] 实例 */
|
||||
private var modifiers: ModifierRules? = null
|
||||
|
||||
/**
|
||||
* [Method] 名称
|
||||
*
|
||||
@@ -69,6 +73,15 @@ class MethodFinder(
|
||||
*/
|
||||
var name = ""
|
||||
|
||||
/**
|
||||
* [Method] 参数个数
|
||||
*
|
||||
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||
*
|
||||
* 若参数个数小于零则忽略并使用 [param]
|
||||
*/
|
||||
var paramCount = -1
|
||||
|
||||
/**
|
||||
* [Method] 返回值
|
||||
*
|
||||
@@ -76,29 +89,38 @@ class MethodFinder(
|
||||
*/
|
||||
var returnType: Class<*>? = null
|
||||
|
||||
/**
|
||||
* [Method] 筛选条件
|
||||
*
|
||||
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Method]
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||
modifiers = ModifierRules().apply(initiate)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Method] 参数
|
||||
*
|
||||
* 如果同时使用了 [paramCount] 则 [paramTypes] 的数量必须与 [paramCount] 完全匹配
|
||||
*
|
||||
* - ❗无参 [Method] 不要使用此方法
|
||||
*
|
||||
* - ❗有参 [Method] 必须使用此方法设定参数
|
||||
* - ❗有参 [Method] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||
* @param paramType 参数类型数组
|
||||
*/
|
||||
fun param(vararg paramType: Class<*>) {
|
||||
if (paramType.isEmpty()) error("paramType is empty, please delete param() method")
|
||||
if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method")
|
||||
paramTypes = paramType
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到方法
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果 [name] 未设置
|
||||
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
private val result
|
||||
get() = if (paramTypes != null)
|
||||
ReflectionUtils.findMethodBestMatch(classSet, returnType, name, *paramTypes!!)
|
||||
else ReflectionUtils.findMethodNoParam(classSet, returnType, name)
|
||||
private val result get() = ReflectionTool.findMethod(classSet, name, modifiers, returnType, paramCount, paramTypes)
|
||||
|
||||
/**
|
||||
* 设置实例
|
||||
@@ -194,7 +216,7 @@ class MethodFinder(
|
||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
||||
}
|
||||
}
|
||||
if (!isFindSuccess) {
|
||||
if (isFindSuccess.not()) {
|
||||
onFailureMsg(
|
||||
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
||||
throwable = lastError,
|
||||
@@ -230,7 +252,7 @@ class MethodFinder(
|
||||
* @param isNoSuch 是否没有找到方法 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
|
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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/3/27.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder.type
|
||||
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
/**
|
||||
* 这是一个 [Member] 描述符定义类
|
||||
*
|
||||
* 可对 R8 混淆后的 [Member] 进行更加详细的定位
|
||||
*/
|
||||
class ModifierRules {
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isPublic = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isPrivate = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isProtected = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isStatic = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isFinal = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isSynchronized = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isVolatile = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isTransient = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isNative = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isInterface = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isAbstract = false
|
||||
|
||||
/** 描述声明使用 */
|
||||
private var isStrict = false
|
||||
|
||||
/** 添加描述 [Member] 类型包含 public */
|
||||
fun asPublic() {
|
||||
isPublic = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 private */
|
||||
fun asPrivate() {
|
||||
isPrivate = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 protected */
|
||||
fun asProtected() {
|
||||
isProtected = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加描述 [Member] 类型包含 static
|
||||
*
|
||||
* 对于任意的静态 [Member] 可添加此描述进行确定
|
||||
*
|
||||
* 特别注意 Kotlin -> Jvm 后的 object 类中的方法并不是静态的
|
||||
*/
|
||||
fun asStatic() {
|
||||
isStatic = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加描述 [Member] 类型包含 final
|
||||
*
|
||||
* 在 Kotlin -> Jvm 后没有 open 标识的 [Member] 和没有任何关联的 [Member] 都将为 final
|
||||
*/
|
||||
fun asFinal() {
|
||||
isFinal = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 synchronized */
|
||||
fun asSynchronized() {
|
||||
isSynchronized = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 volatile */
|
||||
fun asVolatile() {
|
||||
isVolatile = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 transient */
|
||||
fun asTransient() {
|
||||
isTransient = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加描述 [Member] 类型包含 native
|
||||
*
|
||||
* 对于任意 JNI 对接的 [Member] 可添加此描述进行确定
|
||||
*/
|
||||
fun asNative() {
|
||||
isNative = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 interface */
|
||||
fun asInterface() {
|
||||
isInterface = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加描述 [Member] 类型包含 abstract
|
||||
*
|
||||
* 对于任意的抽象 [Member] 可添加此描述进行确定
|
||||
*/
|
||||
fun asAbstract() {
|
||||
isAbstract = true
|
||||
}
|
||||
|
||||
/** 添加描述 [Member] 类型包含 strict */
|
||||
fun asStrict() {
|
||||
isStrict = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 对比 [Member] 类型是否符合条件
|
||||
* @param member 实例
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
internal fun contains(member: Member): Boolean {
|
||||
var conditions = true
|
||||
if (isPublic) conditions = Modifier.isPublic(member.modifiers)
|
||||
if (isPrivate) conditions = conditions && Modifier.isPrivate(member.modifiers)
|
||||
if (isProtected) conditions = conditions && Modifier.isProtected(member.modifiers)
|
||||
if (isStatic) conditions = conditions && Modifier.isStatic(member.modifiers)
|
||||
if (isFinal) conditions = conditions && Modifier.isFinal(member.modifiers)
|
||||
if (isSynchronized) conditions = conditions && Modifier.isSynchronized(member.modifiers)
|
||||
if (isVolatile) conditions = conditions && Modifier.isVolatile(member.modifiers)
|
||||
if (isTransient) conditions = conditions && Modifier.isTransient(member.modifiers)
|
||||
if (isNative) conditions = conditions && Modifier.isNative(member.modifiers)
|
||||
if (isInterface) conditions = conditions && Modifier.isInterface(member.modifiers)
|
||||
if (isAbstract) conditions = conditions && Modifier.isAbstract(member.modifiers)
|
||||
if (isStrict) conditions = conditions && Modifier.isStrict(member.modifiers)
|
||||
return conditions
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
var conditions = ""
|
||||
if (isPublic) conditions += "<public> "
|
||||
if (isPrivate) conditions += "<private> "
|
||||
if (isProtected) conditions += "<protected> "
|
||||
if (isStatic) conditions += "<static> "
|
||||
if (isFinal) conditions += "<final> "
|
||||
if (isSynchronized) conditions += "<synchronized> "
|
||||
if (isVolatile) conditions += "<volatile> "
|
||||
if (isTransient) conditions += "<transient> "
|
||||
if (isNative) conditions += "<native> "
|
||||
if (isInterface) conditions += "<interface> "
|
||||
if (isAbstract) conditions += "<abstract> "
|
||||
if (isStrict) conditions += "<strict> "
|
||||
return "[${conditions.trim()}]"
|
||||
}
|
||||
}
|
@@ -33,7 +33,8 @@ import com.highcapable.yukihookapi.hook.bean.HookClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* [Class] 转换为 [HookClass]
|
||||
@@ -80,51 +81,31 @@ fun String.hasClass(loader: ClassLoader?) = try {
|
||||
|
||||
/**
|
||||
* 查找变量是否存在
|
||||
* @param name 名称
|
||||
* @param type 类型 - 不填默认模糊
|
||||
* @param initiate 方法体
|
||||
* @return [Boolean] 是否存在
|
||||
*/
|
||||
fun Class<*>.hasField(name: String, type: Class<*>? = null): Boolean =
|
||||
try {
|
||||
if (type != null)
|
||||
ReflectionUtils.findFieldIfExists(this, type.name, name)
|
||||
else getDeclaredField(name).apply { isAccessible = true }
|
||||
true
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
fun Class<*>.hasField(initiate: FieldFinder.() -> Unit) = field(initiate).ignoredError().isNoSuch.not()
|
||||
|
||||
/**
|
||||
* 查找方法是否存在
|
||||
* @param name 名称
|
||||
* @param paramType params
|
||||
* @param returnType 返回类型 - 不填默认模糊
|
||||
* @param initiate 方法体
|
||||
* @return [Boolean] 是否存在
|
||||
*/
|
||||
fun Class<*>.hasMethod(name: String, vararg paramType: Class<*>, returnType: Class<*>? = null): Boolean =
|
||||
try {
|
||||
if (paramType.isNotEmpty())
|
||||
ReflectionUtils.findMethodBestMatch(this, returnType, name, *paramType)
|
||||
else ReflectionUtils.findMethodNoParam(this, returnType, name)
|
||||
true
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
fun Class<*>.hasMethod(initiate: MethodFinder.() -> Unit) = method(initiate).ignoredError().isNoSuch.not()
|
||||
|
||||
/**
|
||||
* 查找构造方法是否存在
|
||||
* @param paramType params
|
||||
* @param initiate 方法体
|
||||
* @return [Boolean] 是否存在
|
||||
*/
|
||||
fun Class<*>.hasConstructor(vararg paramType: Class<*>): Boolean =
|
||||
try {
|
||||
if (paramType.isNotEmpty())
|
||||
ReflectionUtils.findConstructorExact(this, *paramType)
|
||||
else ReflectionUtils.findConstructorExact(this)
|
||||
true
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
fun Class<*>.hasConstructor(initiate: ConstructorFinder.() -> Unit) = constructor(initiate).ignoredError().isNoSuch.not()
|
||||
|
||||
/**
|
||||
* 查询 [Member] 中匹配的描述符
|
||||
* @param initiate 方法体
|
||||
* @return [Boolean] 是否存在
|
||||
*/
|
||||
fun Member.hasModifiers(initiate: ModifierRules.() -> Unit) = ModifierRules().apply(initiate).contains(this)
|
||||
|
||||
/**
|
||||
* 查找并得到变量
|
||||
@@ -145,4 +126,4 @@ fun Class<*>.method(initiate: MethodFinder.() -> Unit) = MethodFinder(classSet =
|
||||
* @param initiate 查找方法体
|
||||
* @return [ConstructorFinder.Result]
|
||||
*/
|
||||
fun Class<*>.constructor(initiate: ConstructorFinder.() -> Unit) = ConstructorFinder(classSet = this).apply(initiate).build()
|
||||
fun Class<*>.constructor(initiate: ConstructorFinder.() -> Unit) = ConstructorFinder(classSet = this).apply(initiate).build()
|
@@ -41,7 +41,7 @@ import de.robv.android.xposed.XposedBridge
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerD(msg: String, isDisableLog: Boolean = false) {
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerD(msg = msg)
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerD(msg = msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ internal fun yLoggerD(msg: String, isDisableLog: Boolean = false) {
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerI(msg: String, isDisableLog: Boolean = false) {
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerI(msg = msg)
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerI(msg = msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ internal fun yLoggerI(msg: String, isDisableLog: Boolean = false) {
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerW(msg: String, isDisableLog: Boolean = false) {
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerW(msg = msg)
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerW(msg = msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ internal fun yLoggerW(msg: String, isDisableLog: Boolean = false) {
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerE(msg: String, e: Throwable? = null, isDisableLog: Boolean = false) {
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerE(msg = msg, e = e)
|
||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerE(msg = msg, e = e)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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/3/27.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.utils
|
||||
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* 这是一个对 [Member] 查找的工具实现类
|
||||
*/
|
||||
internal object ReflectionTool {
|
||||
|
||||
/** 当前工具类的标签 */
|
||||
private const val TAG = "YukiHookAPI#ReflectionTool"
|
||||
|
||||
/**
|
||||
* 查找任意变量
|
||||
* @param classSet 变量所在类
|
||||
* @param name 变量名称
|
||||
* @param modifiers 变量描述
|
||||
* @param type 变量类型
|
||||
* @return [Field]
|
||||
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||
* @throws NoSuchFieldError 如果找不到变量
|
||||
*/
|
||||
internal fun findField(classSet: Class<*>?, name: String, modifiers: ModifierRules?, type: Class<*>?): Field {
|
||||
var field: Field? = null
|
||||
run {
|
||||
classSet?.declaredFields?.forEach {
|
||||
var conditions = name == it.name
|
||||
if (type != null) conditions = conditions && it.type == type
|
||||
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||
if (conditions) {
|
||||
field = it.apply { isAccessible = true }
|
||||
return@run
|
||||
}
|
||||
} ?: error("Can't find this Field [$name] because classSet is null")
|
||||
}
|
||||
return field ?: throw NoSuchFieldError(
|
||||
"Can't find this Field --> " +
|
||||
"name:[$name] " +
|
||||
"type:[$type] " +
|
||||
"modifiers:${modifiers ?: "[]"} " +
|
||||
"in Class [$classSet] " +
|
||||
"by $TAG"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找任意方法
|
||||
* @param classSet 方法所在类
|
||||
* @param name 方法名称
|
||||
* @param modifiers 方法描述
|
||||
* @param returnType 方法返回值
|
||||
* @param paramCount 方法参数个数
|
||||
* @param paramTypes 方法参数类型
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
internal fun findMethod(
|
||||
classSet: Class<*>?,
|
||||
name: String,
|
||||
modifiers: ModifierRules?,
|
||||
returnType: Class<*>?,
|
||||
paramCount: Int,
|
||||
paramTypes: Array<out Class<*>>?
|
||||
): Method {
|
||||
var method: Method? = null
|
||||
run {
|
||||
classSet?.declaredMethods?.forEach {
|
||||
var conditions = name == it.name
|
||||
if (returnType != null) conditions = conditions && it.returnType == returnType
|
||||
if (paramCount >= 0) conditions = conditions && it.parameterTypes.size == paramCount
|
||||
if (paramTypes != null) conditions = conditions && arrayContentsEq(paramTypes, it.parameterTypes)
|
||||
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||
if (conditions) {
|
||||
method = it.apply { isAccessible = true }
|
||||
return@run
|
||||
}
|
||||
} ?: error("Can't find this Method [$name] because classSet is null")
|
||||
}
|
||||
return method ?: throw NoSuchMethodError(
|
||||
"Can't find this Method --> " +
|
||||
"name:[$name] " +
|
||||
"paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " +
|
||||
"paramTypes:[${paramTypes.typeOfString()}] " +
|
||||
"returnType:[$returnType] " +
|
||||
"modifiers:${modifiers ?: "[]"} " +
|
||||
"in Class [$classSet] " +
|
||||
"by $TAG"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找任意构造方法
|
||||
* @param classSet 构造方法所在类
|
||||
* @param modifiers 构造方法描述
|
||||
* @param paramCount 构造方法参数个数
|
||||
* @param paramTypes 构造方法参数类型
|
||||
* @return [Constructor]
|
||||
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||
* @throws NoSuchMethodError 如果找不到构造方法
|
||||
*/
|
||||
internal fun findConstructor(
|
||||
classSet: Class<*>?,
|
||||
modifiers: ModifierRules?,
|
||||
paramCount: Int,
|
||||
paramTypes: Array<out Class<*>>?
|
||||
): Constructor<*> {
|
||||
var constructor: Constructor<*>? = null
|
||||
run {
|
||||
classSet?.declaredConstructors?.forEach {
|
||||
var conditions = false
|
||||
if (paramCount >= 0) conditions = it.parameterTypes.size == paramCount
|
||||
if (paramTypes != null) conditions = arrayContentsEq(paramTypes, it.parameterTypes)
|
||||
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||
if (conditions) {
|
||||
constructor = it.apply { isAccessible = true }
|
||||
return@run
|
||||
}
|
||||
} ?: error("Can't find this Constructor because classSet is null")
|
||||
}
|
||||
return constructor ?: throw NoSuchMethodError(
|
||||
"Can't find this Constructor --> " +
|
||||
"paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " +
|
||||
"paramTypes:[${paramTypes.typeOfString()}] " +
|
||||
"modifiers:${modifiers ?: "[]"} " +
|
||||
"in Class [$classSet] " +
|
||||
"by $TAG"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数数组文本化内容
|
||||
* @return [String]
|
||||
*/
|
||||
private fun Array<out Class<*>>?.typeOfString() =
|
||||
StringBuilder("(").also { sb ->
|
||||
var isFirst = true
|
||||
if (this == null || isEmpty()) return "()"
|
||||
forEach {
|
||||
if (isFirst) isFirst = false else sb.append(",")
|
||||
sb.append(it.canonicalName)
|
||||
}
|
||||
sb.append(")")
|
||||
}.toString()
|
||||
|
||||
/**
|
||||
* 判断两个数组是否相等
|
||||
*
|
||||
* 复制自 [Class] 中的 [Class.arrayContentsEq]
|
||||
* @param fArray 第一个数组
|
||||
* @param lArray 第二个数组
|
||||
* @return [Boolean] 是否相等
|
||||
*/
|
||||
private fun arrayContentsEq(fArray: Array<out Any>?, lArray: Array<out Any>?) = run {
|
||||
if (fArray != null) when {
|
||||
lArray == null -> fArray.isEmpty()
|
||||
fArray.size != lArray.size -> false
|
||||
else -> {
|
||||
for (i in fArray.indices) if (fArray[i] !== lArray[i]) return@run false
|
||||
true
|
||||
}
|
||||
} else lArray == null || lArray.isEmpty()
|
||||
}
|
||||
}
|
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* 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 zpp0196 on 2019/1/24 0024.
|
||||
* This file is Modified by fankes on 2022/2/2 2240.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseClass;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@DoNotUseClass
|
||||
/**
|
||||
* ReflectionUtils
|
||||
*/
|
||||
public class ReflectionUtils {
|
||||
|
||||
private static final HashMap<String, Field> fieldCache = new HashMap<>();
|
||||
private static final HashMap<String, Method> methodCache = new HashMap<>();
|
||||
|
||||
private static String getParametersString(Class<?>... clazzes) {
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
boolean first = true;
|
||||
for (Class<?> clazz : clazzes) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
sb.append(",");
|
||||
|
||||
if (clazz != null)
|
||||
sb.append(clazz.getCanonicalName());
|
||||
else
|
||||
sb.append("null");
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 适用于查找混淆类型的 abcd 变量
|
||||
*
|
||||
* @param clazz 变量所在类
|
||||
* @param typeName 类型名称
|
||||
* @param fieldName 变量名
|
||||
* @return Field
|
||||
* @throws NoSuchFieldException 如果找不到变量
|
||||
*/
|
||||
public static Field findFieldIfExists(Class<?> clazz, String typeName, String fieldName) throws NoSuchFieldException {
|
||||
String fullFieldName = "name:[" + fieldName + "] type:[" + typeName + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
||||
if (!fieldCache.containsKey(fullFieldName)) {
|
||||
if (clazz != null && !TextUtils.isEmpty(typeName) && !TextUtils.isEmpty(fieldName)) {
|
||||
Class<?> clz = clazz;
|
||||
do {
|
||||
for (Field field : clz.getDeclaredFields()) {
|
||||
if (field.getType()
|
||||
.getName()
|
||||
.equals(typeName) && field.getName()
|
||||
.equals(fieldName)) {
|
||||
field.setAccessible(true);
|
||||
fieldCache.put(fullFieldName, field);
|
||||
return field;
|
||||
}
|
||||
}
|
||||
} while ((clz = clz.getSuperclass()) != null);
|
||||
throw new NoSuchFieldException("Can't find this field --> " + fullFieldName);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
Field field = fieldCache.get(fullFieldName);
|
||||
if (field == null)
|
||||
throw new NoSuchFieldError(fullFieldName);
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 适用于查找混淆类型的 abcd 方法 - 无 param
|
||||
*
|
||||
* @param clazz 方法所在类
|
||||
* @param returnType 返回类型
|
||||
* @param methodName 方法名
|
||||
* @return Method
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
public static Method findMethodNoParam(Class<?> clazz, Class<?> returnType, String methodName) {
|
||||
String fullMethodName = "name:[" + methodName + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
||||
if (!methodCache.containsKey(fullMethodName)) {
|
||||
Method method = findMethodIfExists(clazz, returnType, methodName);
|
||||
methodCache.put(fullMethodName, method);
|
||||
return method;
|
||||
} else {
|
||||
return methodCache.get(fullMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不区分 param 整个类搜索 - 适用于混淆方法 abcd
|
||||
*
|
||||
* @param clazz 方法所在类
|
||||
* @param returnType 返回类型
|
||||
* @param methodName 方法名
|
||||
* @param parameterTypes 方法参数类型数组
|
||||
* @return Method
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
public static Method findMethodBestMatch(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
|
||||
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
||||
if (!methodCache.containsKey(fullMethodName)) {
|
||||
Method method = findMethodIfExists(clazz, returnType, methodName, parameterTypes);
|
||||
methodCache.put(fullMethodName, method);
|
||||
return method;
|
||||
} else {
|
||||
return methodCache.get(fullMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找构造方法
|
||||
*
|
||||
* @param clazz 构造类所在类
|
||||
* @param parameterTypes 构造类方法参数类型数组
|
||||
* @return Constructor
|
||||
* @throws NoSuchMethodError 如果找不到构造类
|
||||
*/
|
||||
public static Constructor<?> findConstructorExact(Class<?> clazz, Class<?>... parameterTypes) {
|
||||
String fullConstructorName = "paramType:[" + getParametersString(parameterTypes) + "in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
||||
try {
|
||||
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
|
||||
constructor.setAccessible(true);
|
||||
return constructor;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError("Can't find this constructor --> " + fullConstructorName);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
||||
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
||||
try {
|
||||
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError("Can't find this method --> " + fullMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method findMethodIfExists(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
|
||||
long l = System.currentTimeMillis();
|
||||
if (clazz != null && !TextUtils.isEmpty(methodName)) {
|
||||
Class<?> clz = clazz;
|
||||
if (returnType == null) return findMethodExact(clazz, methodName, parameterTypes);
|
||||
do {
|
||||
Method[] methods = findMethodsByExactParameters(clazz, returnType, parameterTypes);
|
||||
for (Method method : methods) if (method.getName().equals(methodName)) return method;
|
||||
} while ((clz = clz.getSuperclass()) != null);
|
||||
}
|
||||
throw new IllegalArgumentException("Can't find this method --> name:[" + methodName + "] returnType:[" + returnType.getName() + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder");
|
||||
}
|
||||
|
||||
private static Method[] findMethodsByExactParameters(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes) {
|
||||
List<Method> result = new LinkedList<Method>();
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (returnType != null && returnType != method.getReturnType()) continue;
|
||||
Class<?>[] methodParameterTypes = method.getParameterTypes();
|
||||
if (parameterTypes.length != methodParameterTypes.length) continue;
|
||||
boolean match = true;
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (parameterTypes[i] != methodParameterTypes[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) continue;
|
||||
method.setAccessible(true);
|
||||
result.add(method);
|
||||
}
|
||||
return result.toArray(new Method[result.size()]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user