Added "onAlreadyHooked" method in YukiMemberHookCreater

This commit is contained in:
2022-05-26 03:24:51 +08:00
parent 670a6b39ee
commit 47f37ab88c
3 changed files with 88 additions and 41 deletions

View File

@@ -565,6 +565,7 @@ injectMember {
// Your code here.
}.result {
onHooked {}
onAlreadyHooked {}
ignoredConductFailure()
onHookingFailure {}
// ...
@@ -605,6 +606,24 @@ fun onHooked(initiate: (Member) -> Unit): Result
在首次 Hook 成功后回调。
在重复 Hook 时会回调 `onAlreadyHooked`
##### onAlreadyHooked [method]
```kotlin
fun onAlreadyHooked(initiate: (Member) -> Unit): Result
```
**变更记录**
`v1.0.89` `新增`
**功能描述**
> 监听 `member` 重复 Hook 的回调方法。
!> 同一个 `hookClass` 中的同一个 `member` 不会被 API 重复 Hook若由于各种原因重复 Hook 会回调此方法。
##### onNoSuchMemberFailure [method]
```kotlin

View File

@@ -162,6 +162,9 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
/** Hook 成功时回调 */
private var onHookedCallback: ((Member) -> Unit)? = null
/** 重复 Hook 时回调 */
private var onAlreadyHookedCallback: ((Member) -> Unit)? = null
/** 找不到 [member] 出现错误回调 */
private var onNoSuchMemberFailureCallback: ((Throwable) -> Unit)? = null
@@ -502,11 +505,14 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
if (member != null)
member.also { member ->
runCatching {
(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"))
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookMethod(member, replaceMent)
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)).also {
when {
it.first == null -> error("Hook Member [$member] failed")
it.second -> onAlreadyHookedCallback?.invoke(it.first!!)
else -> onHookedCallback?.invoke(it.first!!)
}
}
}.onFailure {
onHookingFailureCallback?.invoke(it)
onAllFailureCallback?.invoke(it)
@@ -527,24 +533,22 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
else runCatching {
when (hookMemberMode) {
HookMemberMode.HOOK_ALL_METHODS ->
if (isReplaceHookMode)
YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, replaceMent).also {
if (it.isEmpty()) throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
else it.forEach { e -> onHookedCallback?.invoke(e) }
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, replaceMent)
else YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)).also {
when {
it.first.isEmpty() -> throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
it.second -> it.first.forEach { e -> onAlreadyHookedCallback?.invoke(e) }
else -> it.first.forEach { e -> onHookedCallback?.invoke(e) }
}
else YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook).also {
if (it.isEmpty()) throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
else it.forEach { e -> onHookedCallback?.invoke(e) }
}
HookMemberMode.HOOK_ALL_CONSTRUCTORS ->
if (isReplaceHookMode)
YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, replaceMent).also {
if (it.isEmpty()) throw NoSuchMethodError("No Constructor matched")
else it.forEach { e -> onHookedCallback?.invoke(e) }
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, replaceMent)
else YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, beforeAfterHook)).also {
when {
it.first.isEmpty() -> throw NoSuchMethodError("No Constructor matched")
it.second -> it.first.forEach { e -> onAlreadyHookedCallback?.invoke(e) }
else -> it.first.forEach { e -> onHookedCallback?.invoke(e) }
}
else YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, beforeAfterHook).also {
if (it.isEmpty()) throw NoSuchMethodError("No Constructor matched")
else it.forEach { e -> onHookedCallback?.invoke(e) }
}
else -> error("Hooked got a no error possible")
}
@@ -618,6 +622,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
* 监听 [member] Hook 成功的回调方法
*
* 在首次 Hook 成功后回调
*
* 在重复 Hook 时会回调 [onAlreadyHooked]
* @param initiate 回调被 Hook 的 [Member]
* @return [Result] 可继续向下监听
*/
@@ -626,6 +632,18 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
return this
}
/**
* 监听 [member] 重复 Hook 的回调方法
*
* - ❗同一个 [hookClass] 中的同一个 [member] 不会被 API 重复 Hook - 若由于各种原因重复 Hook 会回调此方法
* @param initiate 回调被重复 Hook 的 [Member]
* @return [Result] 可继续向下监听
*/
fun onAlreadyHooked(initiate: (Member) -> Unit): Result {
onAlreadyHookedCallback = initiate
return this
}
/**
* 监听 [member] 不存在发生错误的回调方法
* @param initiate 回调错误

View File

@@ -477,12 +477,12 @@ object YukiHookBridge {
* 对接 [XposedBridge.hookMethod]
* @param hookMethod 需要 Hook 的方法、构造方法
* @param callback 回调
* @return [Member] or null
* @return [Pair] - ([Member] or null,[Boolean] 是否已经 Hook)
*/
internal fun hookMethod(hookMethod: Member?, callback: YukiHookCallback): Member? {
if (hookedMembers.contains(hookMethod.toString())) return hookMethod
internal fun hookMethod(hookMethod: Member?, callback: YukiHookCallback): Pair<Member?, Boolean> {
if (hookedMembers.contains(hookMethod.toString())) return Pair(hookMethod, true)
hookedMembers.add(hookMethod.toString())
return XposedBridge.hookMethod(hookMethod, compatCallback(callback))?.hookedMethod
return Pair(XposedBridge.hookMethod(hookMethod, compatCallback(callback))?.hookedMethod, false)
}
/**
@@ -492,17 +492,22 @@ object YukiHookBridge {
* @param hookClass 当前 Hook 的 [Class]
* @param methodName 方法名
* @param callback 回调
* @return [HashSet] 成功 Hook 的方法数组
* @return [Pair] - ([HashSet] 成功 Hook 的方法数组,[Boolean] 是否已经 Hook)
*/
internal fun hookAllMethods(hookClass: Class<*>?, methodName: String, callback: YukiHookCallback) = HashSet<Member>().also {
val allMethodsName = "$hookClass$methodName"
if (hookedAllMethods.contains(allMethodsName)) {
hookClass?.allMethods { _, method -> if (method.name == methodName) it.add(method) }
return@also
internal fun hookAllMethods(hookClass: Class<*>?, methodName: String, callback: YukiHookCallback): Pair<HashSet<Member>, Boolean> {
var isAlreadyHook = false
val hookedMembers = HashSet<Member>().also {
val allMethodsName = "$hookClass$methodName"
if (hookedAllMethods.contains(allMethodsName)) {
isAlreadyHook = true
hookClass?.allMethods { _, method -> if (method.name == methodName) it.add(method) }
return@also
}
hookedAllMethods.add(allMethodsName)
XposedBridge.hookAllMethods(hookClass, methodName, compatCallback(callback)).takeIf { it.isNotEmpty() }
?.forEach { e -> it.add(e.hookedMethod) }
}
hookedAllMethods.add(allMethodsName)
XposedBridge.hookAllMethods(hookClass, methodName, compatCallback(callback)).takeIf { it.isNotEmpty() }
?.forEach { e -> it.add(e.hookedMethod) }
return Pair(hookedMembers, isAlreadyHook)
}
/**
@@ -511,17 +516,22 @@ object YukiHookBridge {
* 对接 [XposedBridge.hookAllConstructors]
* @param hookClass 当前 Hook 的 [Class]
* @param callback 回调
* @return [HashSet] 成功 Hook 的构造方法数组
* @return [Pair] - ([HashSet] 成功 Hook 的构造方法数组,[Boolean] 是否已经 Hook)
*/
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback) = HashSet<Member>().also {
val allConstructorsName = "$hookClass<init>"
if (hookedAllConstructors.contains(allConstructorsName)) {
hookClass?.allConstructors { _, constructor -> it.add(constructor) }
return@also
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback): Pair<HashSet<Member>, Boolean> {
var isAlreadyHook = false
val hookedMembers = HashSet<Member>().also {
val allConstructorsName = "$hookClass<init>"
if (hookedAllConstructors.contains(allConstructorsName)) {
isAlreadyHook = true
hookClass?.allConstructors { _, constructor -> it.add(constructor) }
return@also
}
hookedAllConstructors.add(allConstructorsName)
XposedBridge.hookAllConstructors(hookClass, compatCallback(callback)).takeIf { it.isNotEmpty() }
?.forEach { e -> it.add(e.hookedMethod) }
}
hookedAllConstructors.add(allConstructorsName)
XposedBridge.hookAllConstructors(hookClass, compatCallback(callback)).takeIf { it.isNotEmpty() }
?.forEach { e -> it.add(e.hookedMethod) }
return Pair(hookedMembers, isAlreadyHook)
}
/**