mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +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` 查找并得到构造方法。
|
||||
|
||||
#### injectMember [method]
|
||||
|
||||
```kotlin
|
||||
inline fun HookParam.injectMember(priority: Int, tag: String, initiate: MemberHookCreater.() -> Unit): MemberHookCreater.Result
|
||||
```
|
||||
|
||||
**变更记录**
|
||||
|
||||
`v1.0.88` `新增`
|
||||
|
||||
**功能描述**
|
||||
|
||||
> 注入要 Hook 的方法、构造类 (嵌套 Hook)。
|
||||
|
||||
#### beforeHook [method]
|
||||
|
||||
```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.type.HookEntryType
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
@@ -79,7 +80,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
|
||||
/** 设置要 Hook 的方法、构造类 */
|
||||
@PublishedApi
|
||||
internal var preHookMembers = HashSet<MemberHookCreater>()
|
||||
internal var preHookMembers = HashMap<String, MemberHookCreater>()
|
||||
|
||||
/**
|
||||
* 得到当前被 Hook 的 [Class]
|
||||
@@ -99,7 +100,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
* @return [MemberHookCreater.Result]
|
||||
*/
|
||||
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 执行入口
|
||||
@@ -109,8 +111,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
@PublishedApi
|
||||
internal fun hook(): Result {
|
||||
if (YukiHookBridge.hasXposedBridge.not()) return Result()
|
||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] */
|
||||
if (packageParam.wrapper?.type == HookEntryType.RESOURCES) return Result()
|
||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] 或 [PackageParam.isHookParamCallback] 已被执行 */
|
||||
if (packageParam.wrapper?.type == HookEntryType.RESOURCES && packageParam.isHookParamCallback.not()) return Result()
|
||||
return if (preHookMembers.isEmpty()) error("Hook Members is empty, hook aborted")
|
||||
else Result().also {
|
||||
Thread {
|
||||
@@ -119,7 +121,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
when {
|
||||
isDisableCreaterRunHook.not() && hookClass.instance != null -> {
|
||||
it.onPrepareHook?.invoke()
|
||||
preHookMembers.forEach { m -> m.hook() }
|
||||
preHookMembers.forEach { (_, m) -> m.hook() }
|
||||
}
|
||||
isDisableCreaterRunHook.not() && hookClass.instance == 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) {
|
||||
|
||||
/** 是否已经执行 Hook */
|
||||
private var isHooked = false
|
||||
|
||||
/** [beforeHook] 回调 */
|
||||
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)
|
||||
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
|
||||
*
|
||||
@@ -408,7 +426,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
/** Hook 执行入口 */
|
||||
@PublishedApi
|
||||
internal fun hook() {
|
||||
if (YukiHookBridge.hasXposedBridge.not() || isDisableMemberRunHook) return
|
||||
if (YukiHookBridge.hasXposedBridge.not() || isHooked || isDisableMemberRunHook) return
|
||||
isHooked = true
|
||||
finder?.printLogIfExist()
|
||||
if (hookClass.instance == null) {
|
||||
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
||||
@@ -453,6 +472,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
beforeHookCallback?.invoke(param)
|
||||
if (beforeHookCallback != null)
|
||||
onHookLogMsg(msg = "Before Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
||||
packageParam.isHookParamCallback = true
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
@@ -467,6 +487,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
afterHookCallback?.invoke(param)
|
||||
if (afterHookCallback != null)
|
||||
onHookLogMsg(msg = "After Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
||||
packageParam.isHookParamCallback = true
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
@@ -479,11 +500,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
if (member != null)
|
||||
member.also { member ->
|
||||
runCatching {
|
||||
if (isReplaceHookMode)
|
||||
(if (isReplaceHookMode)
|
||||
YukiHookBridge.Hooker.hookMethod(member, replaceMent)?.also { onHookedCallback?.invoke(it) }
|
||||
?: error("Hook Member [$member] failed")
|
||||
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 {
|
||||
onHookingFailureCallback?.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.param.PackageParam
|
||||
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.dummy.YukiResources
|
||||
|
||||
@@ -49,7 +50,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
||||
|
||||
/** 设置要 Hook 的 Resources */
|
||||
@PublishedApi
|
||||
internal var preHookResources = HashSet<ResourcesHookCreater>()
|
||||
internal var preHookResources = HashMap<String, ResourcesHookCreater>()
|
||||
|
||||
/**
|
||||
* 注入要 Hook 的 Resources
|
||||
@@ -58,7 +59,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
||||
* @return [ResourcesHookCreater.Result]
|
||||
*/
|
||||
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 执行入口
|
||||
@@ -70,7 +71,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
|
||||
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
|
||||
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) {
|
||||
|
||||
/** 是否已经执行 Hook */
|
||||
private var isHooked = false
|
||||
|
||||
/**
|
||||
* 模块 APP Resources 替换实例
|
||||
* @param resId Resources Id
|
||||
@@ -174,6 +178,8 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
|
||||
/** Hook 执行入口 */
|
||||
@PublishedApi
|
||||
internal fun hook() {
|
||||
if (isHooked) return
|
||||
isHooked = true
|
||||
if (isDisableCreaterRunHook.not()) runCatching {
|
||||
when {
|
||||
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) {
|
||||
|
||||
/** [HookParam] 是否已经执行回调事件 */
|
||||
internal var isHookParamCallback = false
|
||||
|
||||
/**
|
||||
* 用于展示的 APP 包名
|
||||
* @return [String]
|
||||
|
@@ -27,8 +27,23 @@
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.utils
|
||||
|
||||
import android.os.Build
|
||||
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 方法块
|
||||
|
Reference in New Issue
Block a user