mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 10:45:47 +08:00
Fix inner Hook not invoking and fix maybe created duplicate hook
This commit is contained in:
@@ -386,6 +386,20 @@ inline fun HookParam.constructor(initiate: ConstructorFinder.() -> Unit): Constr
|
|||||||
|
|
||||||
> 使用当前 `hookClass` 查找并得到构造方法。
|
> 使用当前 `hookClass` 查找并得到构造方法。
|
||||||
|
|
||||||
|
#### injectMember [method]
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
inline fun HookParam.injectMember(priority: Int, tag: String, initiate: MemberHookCreater.() -> Unit): MemberHookCreater.Result
|
||||||
|
```
|
||||||
|
|
||||||
|
**变更记录**
|
||||||
|
|
||||||
|
`v1.0.88` `新增`
|
||||||
|
|
||||||
|
**功能描述**
|
||||||
|
|
||||||
|
> 注入要 Hook 的方法、构造类 (嵌套 Hook)。
|
||||||
|
|
||||||
#### beforeHook [method]
|
#### beforeHook [method]
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
|
@@ -42,6 +42,7 @@ import com.highcapable.yukihookapi.hook.param.HookParam
|
|||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||||
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
||||||
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||||
|
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Member
|
import java.lang.reflect.Member
|
||||||
@@ -79,7 +80,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
|
|
||||||
/** 设置要 Hook 的方法、构造类 */
|
/** 设置要 Hook 的方法、构造类 */
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal var preHookMembers = HashSet<MemberHookCreater>()
|
internal var preHookMembers = HashMap<String, MemberHookCreater>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到当前被 Hook 的 [Class]
|
* 得到当前被 Hook 的 [Class]
|
||||||
@@ -99,7 +100,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
* @return [MemberHookCreater.Result]
|
* @return [MemberHookCreater.Result]
|
||||||
*/
|
*/
|
||||||
inline fun injectMember(priority: Int = PRIORITY_DEFAULT, tag: String = "Default", initiate: MemberHookCreater.() -> Unit) =
|
inline fun injectMember(priority: Int = PRIORITY_DEFAULT, tag: String = "Default", initiate: MemberHookCreater.() -> Unit) =
|
||||||
MemberHookCreater(priority, tag, packageParam.exhibitName).apply(initiate).apply { preHookMembers.add(this) }.build()
|
MemberHookCreater(priority, tag, packageParam.exhibitName)
|
||||||
|
.apply(initiate).apply { preHookMembers.putIfAbsentCompat(toString(), this) }.build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 执行入口
|
* Hook 执行入口
|
||||||
@@ -109,8 +111,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun hook(): Result {
|
internal fun hook(): Result {
|
||||||
if (YukiHookBridge.hasXposedBridge.not()) return Result()
|
if (YukiHookBridge.hasXposedBridge.not()) return Result()
|
||||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] */
|
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] 或 [PackageParam.isHookParamCallback] 已被执行 */
|
||||||
if (packageParam.wrapper?.type == HookEntryType.RESOURCES) return Result()
|
if (packageParam.wrapper?.type == HookEntryType.RESOURCES && packageParam.isHookParamCallback.not()) return Result()
|
||||||
return if (preHookMembers.isEmpty()) error("Hook Members is empty, hook aborted")
|
return if (preHookMembers.isEmpty()) error("Hook Members is empty, hook aborted")
|
||||||
else Result().also {
|
else Result().also {
|
||||||
Thread {
|
Thread {
|
||||||
@@ -119,7 +121,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
when {
|
when {
|
||||||
isDisableCreaterRunHook.not() && hookClass.instance != null -> {
|
isDisableCreaterRunHook.not() && hookClass.instance != null -> {
|
||||||
it.onPrepareHook?.invoke()
|
it.onPrepareHook?.invoke()
|
||||||
preHookMembers.forEach { m -> m.hook() }
|
preHookMembers.forEach { (_, m) -> m.hook() }
|
||||||
}
|
}
|
||||||
isDisableCreaterRunHook.not() && hookClass.instance == null ->
|
isDisableCreaterRunHook.not() && hookClass.instance == null ->
|
||||||
if (onHookClassNotFoundFailureCallback == null)
|
if (onHookClassNotFoundFailureCallback == null)
|
||||||
@@ -140,6 +142,9 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
*/
|
*/
|
||||||
inner class MemberHookCreater(private val priority: Int, internal val tag: String, internal val packageName: String) {
|
inner class MemberHookCreater(private val priority: Int, internal val tag: String, internal val packageName: String) {
|
||||||
|
|
||||||
|
/** 是否已经执行 Hook */
|
||||||
|
private var isHooked = false
|
||||||
|
|
||||||
/** [beforeHook] 回调 */
|
/** [beforeHook] 回调 */
|
||||||
private var beforeHookCallback: (HookParam.() -> Unit)? = null
|
private var beforeHookCallback: (HookParam.() -> Unit)? = null
|
||||||
|
|
||||||
@@ -301,6 +306,19 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
if (hookClass.instance == null) ConstructorFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable)
|
if (hookClass.instance == null) ConstructorFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable)
|
||||||
else ConstructorFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build()
|
else ConstructorFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注入要 Hook 的方法、构造类 (嵌套 Hook)
|
||||||
|
* @param priority Hook 优先级 - 默认 [PRIORITY_DEFAULT]
|
||||||
|
* @param tag 可设置标签 - 在发生错误时方便进行调试
|
||||||
|
* @param initiate 方法体
|
||||||
|
* @return [MemberHookCreater.Result]
|
||||||
|
*/
|
||||||
|
inline fun HookParam.injectMember(
|
||||||
|
priority: Int = PRIORITY_DEFAULT,
|
||||||
|
tag: String = "InnerDefault",
|
||||||
|
initiate: MemberHookCreater.() -> Unit
|
||||||
|
) = this@YukiMemberHookCreater.injectMember(priority, tag, initiate).also { this@YukiMemberHookCreater.hook() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在方法执行完成前 Hook
|
* 在方法执行完成前 Hook
|
||||||
*
|
*
|
||||||
@@ -408,7 +426,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
/** Hook 执行入口 */
|
/** Hook 执行入口 */
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun hook() {
|
internal fun hook() {
|
||||||
if (YukiHookBridge.hasXposedBridge.not() || isDisableMemberRunHook) return
|
if (YukiHookBridge.hasXposedBridge.not() || isHooked || isDisableMemberRunHook) return
|
||||||
|
isHooked = true
|
||||||
finder?.printLogIfExist()
|
finder?.printLogIfExist()
|
||||||
if (hookClass.instance == null) {
|
if (hookClass.instance == null) {
|
||||||
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
||||||
@@ -453,6 +472,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
beforeHookCallback?.invoke(param)
|
beforeHookCallback?.invoke(param)
|
||||||
if (beforeHookCallback != null)
|
if (beforeHookCallback != null)
|
||||||
onHookLogMsg(msg = "Before Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
onHookLogMsg(msg = "Before Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
||||||
|
packageParam.isHookParamCallback = true
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
onConductFailureCallback?.invoke(param, it)
|
onConductFailureCallback?.invoke(param, it)
|
||||||
onAllFailureCallback?.invoke(it)
|
onAllFailureCallback?.invoke(it)
|
||||||
@@ -467,6 +487,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
afterHookCallback?.invoke(param)
|
afterHookCallback?.invoke(param)
|
||||||
if (afterHookCallback != null)
|
if (afterHookCallback != null)
|
||||||
onHookLogMsg(msg = "After Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
onHookLogMsg(msg = "After Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
||||||
|
packageParam.isHookParamCallback = true
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
onConductFailureCallback?.invoke(param, it)
|
onConductFailureCallback?.invoke(param, it)
|
||||||
onAllFailureCallback?.invoke(it)
|
onAllFailureCallback?.invoke(it)
|
||||||
@@ -479,11 +500,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
if (member != null)
|
if (member != null)
|
||||||
member.also { member ->
|
member.also { member ->
|
||||||
runCatching {
|
runCatching {
|
||||||
if (isReplaceHookMode)
|
(if (isReplaceHookMode)
|
||||||
YukiHookBridge.Hooker.hookMethod(member, replaceMent)?.also { onHookedCallback?.invoke(it) }
|
YukiHookBridge.Hooker.hookMethod(member, replaceMent)?.also { onHookedCallback?.invoke(it) }
|
||||||
?: error("Hook Member [$member] failed")
|
?: error("Hook Member [$member] failed")
|
||||||
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)?.also { onHookedCallback?.invoke(it) }
|
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)?.also { onHookedCallback?.invoke(it) }
|
||||||
?: error("Hook Member [$member] failed")
|
?: error("Hook Member [$member] failed")).run { packageParam.isHookParamCallback = true }
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
onHookingFailureCallback?.invoke(it)
|
onHookingFailureCallback?.invoke(it)
|
||||||
onAllFailureCallback?.invoke(it)
|
onAllFailureCallback?.invoke(it)
|
||||||
|
@@ -36,6 +36,7 @@ import com.highcapable.yukihookapi.hook.log.yLoggerE
|
|||||||
import com.highcapable.yukihookapi.hook.log.yLoggerI
|
import com.highcapable.yukihookapi.hook.log.yLoggerI
|
||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||||
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
||||||
|
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
|
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
|||||||
|
|
||||||
/** 设置要 Hook 的 Resources */
|
/** 设置要 Hook 的 Resources */
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal var preHookResources = HashSet<ResourcesHookCreater>()
|
internal var preHookResources = HashMap<String, ResourcesHookCreater>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注入要 Hook 的 Resources
|
* 注入要 Hook 的 Resources
|
||||||
@@ -58,7 +59,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
|||||||
* @return [ResourcesHookCreater.Result]
|
* @return [ResourcesHookCreater.Result]
|
||||||
*/
|
*/
|
||||||
inline fun injectResource(tag: String = "Default", initiate: ResourcesHookCreater.() -> Unit) =
|
inline fun injectResource(tag: String = "Default", initiate: ResourcesHookCreater.() -> Unit) =
|
||||||
ResourcesHookCreater(tag).apply(initiate).apply { preHookResources.add(this) }.build()
|
ResourcesHookCreater(tag).apply(initiate).apply { preHookResources.putIfAbsentCompat(toString(), this) }.build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 执行入口
|
* Hook 执行入口
|
||||||
@@ -70,7 +71,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
|||||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
|
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
|
||||||
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
|
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
|
||||||
if (preHookResources.isEmpty()) error("Hook Resources is empty, hook aborted")
|
if (preHookResources.isEmpty()) error("Hook Resources is empty, hook aborted")
|
||||||
preHookResources.forEach { it.hook() }
|
preHookResources.forEach { (_, r) -> r.hook() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,6 +82,9 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
|||||||
*/
|
*/
|
||||||
inner class ResourcesHookCreater(private val tag: String) {
|
inner class ResourcesHookCreater(private val tag: String) {
|
||||||
|
|
||||||
|
/** 是否已经执行 Hook */
|
||||||
|
private var isHooked = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模块 APP Resources 替换实例
|
* 模块 APP Resources 替换实例
|
||||||
* @param resId Resources Id
|
* @param resId Resources Id
|
||||||
@@ -174,6 +178,8 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
|||||||
/** Hook 执行入口 */
|
/** Hook 执行入口 */
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun hook() {
|
internal fun hook() {
|
||||||
|
if (isHooked) return
|
||||||
|
isHooked = true
|
||||||
if (isDisableCreaterRunHook.not()) runCatching {
|
if (isDisableCreaterRunHook.not()) runCatching {
|
||||||
when {
|
when {
|
||||||
conditions == null -> yLoggerE(msg = "You must set the conditions before hook a Resources [$tag]")
|
conditions == null -> yLoggerE(msg = "You must set the conditions before hook a Resources [$tag]")
|
||||||
|
@@ -56,6 +56,9 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
|
|||||||
*/
|
*/
|
||||||
open class PackageParam(@PublishedApi internal var wrapper: PackageParamWrapper? = null) {
|
open class PackageParam(@PublishedApi internal var wrapper: PackageParamWrapper? = null) {
|
||||||
|
|
||||||
|
/** [HookParam] 是否已经执行回调事件 */
|
||||||
|
internal var isHookParamCallback = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于展示的 APP 包名
|
* 用于展示的 APP 包名
|
||||||
* @return [String]
|
* @return [String]
|
||||||
|
@@ -27,8 +27,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.highcapable.yukihookapi.hook.utils
|
package com.highcapable.yukihookapi.hook.utils
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
|
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不重复写入 [HashMap]
|
||||||
|
*
|
||||||
|
* 兼容旧版本 Android
|
||||||
|
* @param key Key
|
||||||
|
* @param value Value
|
||||||
|
*/
|
||||||
|
@YukiPrivateApi
|
||||||
|
inline fun <reified K, V> HashMap<K, V>.putIfAbsentCompat(key: K, value: V) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||||
|
putIfAbsent(key, value)
|
||||||
|
else get(key) ?: put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算方法执行耗时
|
* 计算方法执行耗时
|
||||||
* @param block 方法块
|
* @param block 方法块
|
||||||
|
Reference in New Issue
Block a user