diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..4bec4ea8
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..a55e7a17
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt
new file mode 100644
index 00000000..922f8441
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt
@@ -0,0 +1,40 @@
+/**
+ * MIT License
+ *
+ * Copyright (C) 2022 HighCapable
+ *
+ * This file is part of YukiHookAPI.
+ *
+ * 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/2/9.
+ */
+package com.highcapable.yukihookapi.hook.bean
+
+/**
+ * 自适应异常 [Class] 接管类
+ * @param instance 实例
+ * @param name 完整名称
+ * @param throwable 异常
+ */
+class HookClass(
+ var instance: Class<*>? = null,
+ var name: String,
+ var throwable: Throwable? = null
+)
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt
index dc0c4361..b649fd70 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt
@@ -31,6 +31,7 @@ package com.highcapable.yukihookapi.hook.core
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
+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
@@ -38,6 +39,7 @@ import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.param.HookParam
import com.highcapable.yukihookapi.hook.param.PackageParam
+import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XposedBridge
@@ -49,9 +51,9 @@ import java.lang.reflect.Member
*
* 这是一个 API 对接类 - 实现原生对接 [XposedBridge]
* @param packageParam 需要传入 [PackageParam] 实现方法调用
- * @param hookClass 要 Hook 的 [Class] - 必须使用当前 Hook APP 的 [ClassLoader] 装载
+ * @param hookClass 要 Hook 的 [HookClass] 实例
*/
-class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Class<*>) {
+class YukiHookCreater(private val packageParam: PackageParam, private val hookClass: HookClass) {
/**
* Hook 全部方法的标识
@@ -61,6 +63,16 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
/** 设置要 Hook 的方法、构造类 */
private var hookMembers = HashMap()
+ /**
+ * 得到当前被 Hook 的 [Class]
+ *
+ * - ❗不推荐直接使用 - 万一得不到 [Class] 对象则会无法处理异常导致崩溃
+ * @return [Class]
+ * @throws IllegalStateException 如果当前 [Class] 未被正确装载
+ */
+ val thisClass
+ get() = hookClass.instance ?: error("Cannot get hook class \"${hookClass.name}\" cause ${hookClass.throwable?.message}")
+
/**
* 注入要 Hook 的方法、构造类
* @param tag 可设置标签 - 在发生错误时方便进行调试
@@ -164,9 +176,10 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
* @return [MethodFinder.Result]
*/
fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result {
+ if (hookClass.instance == null) return MethodFinder(hookInstance = this).failure(hookClass.throwable)
hookAllMembers = HookAllMembers.HOOK_NONE
isHookMemberSetup = true
- return MethodFinder(hookInstance = this, hookClass).apply(initiate).build()
+ return MethodFinder(hookInstance = this, hookClass.instance).apply(initiate).build()
}
/**
@@ -177,9 +190,10 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
* @return [ConstructorFinder.Result]
*/
fun constructor(initiate: ConstructorFinder.() -> Unit = {}): ConstructorFinder.Result {
+ if (hookClass.instance == null) return ConstructorFinder(hookInstance = this).failure(hookClass.throwable)
hookAllMembers = HookAllMembers.HOOK_NONE
isHookMemberSetup = true
- return ConstructorFinder(hookInstance = this, hookClass).apply(initiate).build()
+ return ConstructorFinder(hookInstance = this, hookClass.instance).apply(initiate).build()
}
/**
@@ -188,7 +202,8 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
* @return [FieldFinder.Result]
*/
fun HookParam.field(initiate: FieldFinder.() -> Unit) =
- FieldFinder(hookInstance = this@MemberHookCreater, hookClass).apply(initiate).build()
+ if (hookClass.instance == null) FieldFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable)
+ else FieldFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build()
/**
* 在方法执行完成前 Hook
@@ -298,11 +313,20 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
@DoNotUseMethod
fun hook() {
if (!YukiHookAPI.hasXposedBridge) return
+ if (hookClass.instance == null) {
+ (hookClass.throwable ?: Throwable("Failed Hooked Class [${hookClass.name}]")).also {
+ onHookingFailureCallback?.invoke(it)
+ onAllFailureCallback?.invoke(it)
+ if (onHookingFailureCallback == null && onAllFailureCallback == null)
+ onHookFailureMsg(it)
+ }
+ return
+ }
/** 定义替换 Hook 回调方法体 */
val replaceMent = object : XC_MethodReplacement() {
override fun replaceHookedMethod(baseParam: MethodHookParam?): Any? {
if (baseParam == null) return null
- return HookParam(baseParam).let { param ->
+ return HookParam(HookParamWrapper(baseParam)).let { param ->
try {
if (replaceHookCallback != null)
onHookLogMsg(msg = "Replace Hook Member [${member ?: "All Member $allMethodsName"}] done [$tag]")
@@ -322,7 +346,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
val beforeAfterHook = object : XC_MethodHook() {
override fun beforeHookedMethod(baseParam: MethodHookParam?) {
if (baseParam == null) return
- HookParam(baseParam).also { param ->
+ HookParam(HookParamWrapper(baseParam)).also { param ->
runCatching {
beforeHookCallback?.invoke(param)
if (beforeHookCallback != null)
@@ -338,7 +362,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
override fun afterHookedMethod(baseParam: MethodHookParam?) {
if (baseParam == null) return
- HookParam(baseParam).also { param ->
+ HookParam(HookParamWrapper(baseParam)).also { param ->
runCatching {
afterHookCallback?.invoke(param)
if (afterHookCallback != null)
@@ -379,12 +403,12 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
when (hookAllMembers) {
HookAllMembers.HOOK_ALL_METHODS ->
if (isReplaceHookMode)
- XposedBridge.hookAllMethods(hookClass, allMethodsName, replaceMent)
- else XposedBridge.hookAllMethods(hookClass, allMethodsName, beforeAfterHook)
+ XposedBridge.hookAllMethods(hookClass.instance, allMethodsName, replaceMent)
+ else XposedBridge.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)
HookAllMembers.HOOK_ALL_CONSTRUCTORS ->
if (isReplaceHookMode)
- XposedBridge.hookAllConstructors(hookClass, replaceMent)
- else XposedBridge.hookAllConstructors(hookClass, beforeAfterHook)
+ XposedBridge.hookAllConstructors(hookClass.instance, replaceMent)
+ else XposedBridge.hookAllConstructors(hookClass.instance, beforeAfterHook)
else -> error("Hooked got a no error possible")
}
}.onFailure {
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt
index 24f29e9b..5aaf83ea 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt
@@ -44,7 +44,7 @@ import java.lang.reflect.Constructor
* @param hookInstance 当前 Hook 实例
* @param hookClass 当前被 Hook 的 [Class]
*/
-class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
+class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
/** [Constructor] 参数数组 */
private var params: Array>? = null
@@ -91,6 +91,16 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea
Result(isNoSuch = true, e)
}
+ /**
+ * 创建一个异常结果
+ *
+ * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
+ * @param throwable 异常
+ * @return [Result]
+ */
+ @DoNotUseMethod
+ fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
+
/**
* 发生错误时输出日志
* @param msg 消息日志
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt
index 1473e865..91ddfa72 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt
@@ -43,7 +43,7 @@ import java.lang.reflect.Field
* @param hookInstance 当前 Hook 实例
* @param hookClass 当前被 Hook 的 [Class]
*/
-class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
+class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
/** 当前找到的 [Field] */
private var fieldInstance: Field? = null
@@ -85,6 +85,16 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p
Result(isNoSuch = true, e)
}
+ /**
+ * 创建一个异常结果
+ *
+ * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
+ * @param throwable 异常
+ * @return [Result]
+ */
+ @DoNotUseMethod
+ fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
+
/**
* Field 查找结果实现类
*
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt
index d47351d2..764cc269 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt
@@ -44,7 +44,7 @@ import java.lang.reflect.Method
* @param hookInstance 当前 Hook 实例
* @param hookClass 当前 Hook 的 Class
*/
-class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
+class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
/** [Method] 参数数组 */
private var params: Array>? = null
@@ -109,6 +109,16 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater,
Result(isNoSuch = true, e)
}
+ /**
+ * 创建一个异常结果
+ *
+ * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
+ * @param throwable 异常
+ * @return [Result]
+ */
+ @DoNotUseMethod
+ fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
+
/**
* 发生错误时输出日志
* @param msg 消息日志
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
index 23fcc560..cb1320cc 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt
@@ -29,6 +29,7 @@
package com.highcapable.yukihookapi.hook.factory
+import com.highcapable.yukihookapi.hook.bean.HookClass
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Method
@@ -52,6 +53,18 @@ val String.hasClass
false
}
+/**
+ * [Class] 转换为 [HookClass]
+ * @return [HookClass]
+ */
+val Class<*>.hookClass get() = HookClass(instance = this, name)
+
+/**
+ * [HookClass] 转换为 [Class]
+ * @return [Class] or null
+ */
+val HookClass.clazz get() = instance
+
/**
* 查找方法是否存在
* @param name 名称
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/HookParam.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/HookParam.kt
index 1a52905d..c60eecb6 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/HookParam.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/HookParam.kt
@@ -29,42 +29,46 @@
package com.highcapable.yukihookapi.hook.param
-import de.robv.android.xposed.XC_MethodHook
+import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import java.lang.reflect.Constructor
-import java.lang.reflect.Method
+import java.lang.reflect.Member
/**
* Hook 方法、构造类的目标对象实现类
- * @param baseParam 对接 Xposed API 的 [XC_MethodHook.MethodHookParam]
+ * @param wrapper [HookParam] 的参数包装类实例
*/
-class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
+class HookParam(private val wrapper: HookParamWrapper) {
/**
- * 获取当前 [method] or [constructor] 的参数对象数组
+ * 获取当前 [member] or [constructor] 的参数对象数组
* @return [Array]
*/
- val args get() = baseParam.args ?: arrayOf(0)
+ val args get() = wrapper.args ?: arrayOf(0)
/**
- * 获取当前 [method] or [constructor] 的参数对象数组第一位
+ * 获取当前 [member] or [constructor] 的参数对象数组第一位
* @return [Array]
* @throws IllegalStateException 如果数组为空或对象为空
*/
- val firstArgs get() = args[0] ?: error("HookParam args[0] with a non-null object")
+ val firstArgs
+ get() = if (args.isNotEmpty()) args[0] ?: error("HookParam args[0] with a non-null object")
+ else error("HookParam args is empty")
/**
- * 获取当前 [method] or [constructor] 的参数对象数组最后一位
+ * 获取当前 [member] or [constructor] 的参数对象数组最后一位
* @return [Array]
* @throws IllegalStateException 如果数组为空或对象为空
*/
- val lastArgs get() = args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
+ val lastArgs
+ get() = if (args.isNotEmpty()) args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
+ else error("HookParam args is empty")
/**
* 获取当前 Hook 实例的对象
* @return [Any]
* @throws IllegalStateException 如果对象为空
*/
- val instance get() = baseParam.thisObject ?: error("HookParam must with a non-null object")
+ val instance get() = wrapper.instance ?: error("HookParam must with a non-null instance")
/**
* 获取当前 Hook 实例的类对象
@@ -73,27 +77,27 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
val instanceClass get() = instance.javaClass
/**
- * 获取当前 Hook 的方法
- * @return [Method]
- * @throws IllegalStateException 如果方法为空或方法类型不是 [Method]
+ * 获取当前 Hook 的方法、构造方法
+ * @return [Member]
+ * @throws IllegalStateException 如果 [Member] 是空的
*/
- val method get() = baseParam.method as? Method? ?: error("Current hook method type is wrong or null")
+ val member get() = wrapper.member ?: error("Current hook member type is wrong or null")
/**
* 获取当前 Hook 的构造方法
* @return [Constructor]
* @throws IllegalStateException 如果方法为空或方法类型不是 [Constructor]
*/
- val constructor get() = baseParam.method as? Constructor<*>? ?: error("Current hook constructor type is wrong or null")
+ val constructor get() = wrapper.member as? Constructor<*>? ?: error("Current hook constructor type is wrong or null")
/**
- * 获取、设置当前 [method] or [constructor] 的返回值
+ * 获取、设置当前 [member] or [constructor] 的返回值
* @return [Any] or null
*/
var result: Any?
- get() = baseParam.result
+ get() = wrapper.result
set(value) {
- baseParam.result = value
+ wrapper.result = value
}
/**
@@ -101,10 +105,10 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
* @return [T]
* @throws IllegalStateException 如果对象为空或对象类型不是 [T]
*/
- inline fun instance() = instance as? T? ?: error("HookParam object cannot cast to ${T::class.java.name}")
+ inline fun instance() = instance as? T? ?: error("HookParam instance cannot cast to ${T::class.java.name}")
/**
- * 获取当前 [method] or [constructor] 的参数实例化对象类
+ * 获取当前 [member] or [constructor] 的参数实例化对象类
* @param index 参数对象数组下标 - 默认是 0
* @return [ArgsModifyer]
*/
@@ -151,7 +155,7 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
fun set(any: T?) {
if (args.isEmpty()) error("HookParam method args is empty,mabe not has args")
if (index > args.lastIndex) error("HookParam method args index out of bounds,max is ${args.lastIndex}")
- baseParam.args[index] = any
+ wrapper.setArgs(index, any)
}
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
index 7dad5b5e..cc3b1091 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt
@@ -31,16 +31,18 @@ package com.highcapable.yukihookapi.hook.param
import android.content.pm.ApplicationInfo
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
+import com.highcapable.yukihookapi.hook.bean.HookClass
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
+import com.highcapable.yukihookapi.hook.factory.hookClass
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
/**
* 装载 Hook 的目标 APP 入口对象实现类
- * @param baseParam [PackageParam] 的参数包装类实例 - 默认是空的
+ * @param wrapper [PackageParam] 的参数包装类实例 - 默认是空的
*/
-open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
+open class PackageParam(private var wrapper: PackageParamWrapper? = null) {
/**
* 获取当前 APP 的 [ClassLoader]
@@ -48,13 +50,13 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
* @throws IllegalStateException 如果 [ClassLoader] 是空的
*/
val appClassLoader
- get() = baseParam?.appClassLoader ?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
+ get() = wrapper?.appClassLoader ?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
/**
* 获取当前 APP 的 [ApplicationInfo]
* @return [ApplicationInfo]
*/
- val appInfo get() = baseParam?.appInfo ?: ApplicationInfo()
+ val appInfo get() = wrapper?.appInfo ?: ApplicationInfo()
/**
* 获取当前 APP 的进程名称
@@ -62,13 +64,13 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
* 默认的进程名称是 [packageName]
* @return [String]
*/
- val processName get() = baseParam?.processName ?: packageName
+ val processName get() = wrapper?.processName ?: packageName
/**
* 获取当前 APP 的包名
* @return [String]
*/
- val packageName get() = baseParam?.packageName ?: ""
+ val packageName get() = wrapper?.packageName ?: ""
/**
* 获取当前 APP 是否为第一个 Application
@@ -78,20 +80,26 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
/**
* 获得当前使用的存取数据对象缓存实例
- *
* @return [YukiHookModulePrefs]
*/
val prefs by lazy { YukiHookModulePrefs() }
+ /**
+ * 获得当前使用的存取数据对象缓存实例
+ * @param name 自定义 Sp 存储名称
+ * @return [YukiHookModulePrefs]
+ */
+ fun prefs(name: String) = prefs.name(name)
+
/**
* 赋值并克隆另一个 [PackageParam]
*
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
- * @param another 另一个 [PackageParam]
+ * @param anotherParam 另一个 [PackageParam]
*/
@DoNotUseMethod
- internal fun baseAssignInstance(another: PackageParam) {
- this.baseParam = another.baseParam
+ internal fun baseAssignInstance(anotherParam: PackageParam) {
+ thisParam.wrapper = anotherParam.wrapper
}
/**
@@ -111,27 +119,46 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
*/
fun loadHooker(hooker: YukiBaseHooker) = hooker.assignInstance(packageParam = this)
- /**
- * 将目标 [Class] 绑定到 [appClassLoader]
- *
- * - ❗请注意未绑定到 [appClassLoader] 的 [Class] 不能被装载 - 调用 [hook] 方法会自动绑定
- * @return [Class]
- * @throws NoClassDefFoundError 如果找不到类会报错
- */
- fun Class<*>.bind(): Class<*> = appClassLoader.loadClass(name)
-
/**
* 通过 [appClassLoader] 查询并装载 [Class]
* @param name 类名
- * @return [Class]
- * @throws NoClassDefFoundError 如果找不到类会报错
+ * @return [HookClass]
*/
- fun findClass(name: String): Class<*> = appClassLoader.loadClass(name)
+ fun findClass(name: String) = try {
+ appClassLoader.loadClass(name).hookClass
+ } catch (e: Throwable) {
+ HookClass(name = name, throwable = e)
+ }
/**
* Hook 方法、构造类
* @param initiate 方法体
*/
fun Class<*>.hook(initiate: YukiHookCreater.() -> Unit) =
- YukiHookCreater(packageParam = this@PackageParam, hookClass = bind()).apply(initiate).hook()
+ YukiHookCreater(packageParam = thisParam, hookClass = hookClass.bind()).apply(initiate).hook()
+
+ /**
+ * Hook 方法、构造类
+ * @param initiate 方法体
+ */
+ fun HookClass.hook(initiate: YukiHookCreater.() -> Unit) =
+ YukiHookCreater(packageParam = thisParam, hookClass = bind()).apply(initiate).hook()
+
+ /**
+ * 将目标 [Class] 绑定到 [appClassLoader]
+ *
+ * - ❗请注意未绑定到 [appClassLoader] 的 [Class] 不能被装载 - 调用 [hook] 方法会自动绑定
+ * @return [HookClass]
+ */
+ private fun HookClass.bind() = try {
+ appClassLoader.loadClass(name).hookClass
+ } catch (e: Throwable) {
+ HookClass(name = name, throwable = e)
+ }
+
+ /**
+ * 返回自身实例
+ * @return [PackageParam]
+ */
+ private val thisParam get() = this
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/HookParamWrapper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/HookParamWrapper.kt
new file mode 100644
index 00000000..8f3f19ee
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/HookParamWrapper.kt
@@ -0,0 +1,76 @@
+/**
+ * MIT License
+ *
+ * Copyright (C) 2022 HighCapable
+ *
+ * This file is part of YukiHookAPI.
+ *
+ * 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/2/9.
+ */
+package com.highcapable.yukihookapi.hook.param.wrapper
+
+import com.highcapable.yukihookapi.hook.param.HookParam
+import de.robv.android.xposed.XC_MethodHook
+import java.lang.reflect.Member
+
+/**
+ * 用于包装 [HookParam]
+ * @param baseParam 对接 [XC_MethodHook.MethodHookParam]
+ */
+class HookParamWrapper(private val baseParam: XC_MethodHook.MethodHookParam) {
+
+ /**
+ * [Member] 实例
+ * @return [Member] or null
+ */
+ val member: Member? get() = baseParam.method
+
+ /**
+ * 当前实例对象
+ * @return [Any] or null
+ */
+ val instance: Any? get() = baseParam.thisObject
+
+ /**
+ * 方法、构造方法数组
+ * @return [Array] or null
+ */
+ val args: Array? get() = baseParam.args
+
+ /**
+ * 方法、设置方法结果
+ * @return [Any] or null
+ */
+ var result: Any?
+ get() = baseParam.result
+ set(value) {
+ baseParam.result = value
+ }
+
+ /**
+ * 设置方法参数
+ * @param index 数组下标
+ * @param any 参数对象实例
+ */
+ fun setArgs(index: Int, any: Any?) {
+ baseParam.args[index] = any
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt
index a1610543..6c5dfa33 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt
@@ -51,15 +51,15 @@ import java.io.File
*
* - 详见 [New XSharedPreferences](https://github.com/LSPosed/LSPosed/wiki/New-XSharedPreferences#for-the-module)
*
- * - 未使用 LSposed 环境请将你的模块 API 降至 26 以下 - YukiHookAPI 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
+ * - 未使用 LSPosed 环境请将你的模块 API 降至 26 以下 - YukiHookAPI 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
*
* - ❗当你在模块中存取数据的时候 [context] 必须不能是空的
* @param context 上下文实例 - 默认空
*/
class YukiHookModulePrefs(private val context: Context? = null) {
- /** 存储名称 - 包名 + _preferences */
- private val prefsName get() = "${YukiHookAPI.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
+ /** 存储名称 - 默认包名 + _preferences */
+ private var prefsName = "${YukiHookAPI.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
/** 是否为 Xposed 环境 */
private val isXposedEnvironment = YukiHookAPI.hasXposedBridge
@@ -83,26 +83,24 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获得 [XSharedPreferences] 对象
* @return [XSharedPreferences]
*/
- private val xPref by lazy {
- XSharedPreferences(YukiHookAPI.modulePackageName, prefsName).apply {
+ private val xPref
+ get() = XSharedPreferences(YukiHookAPI.modulePackageName, prefsName).apply {
makeWorldReadable()
reload()
}
- }
/**
* 获得 [SharedPreferences] 对象
* @return [SharedPreferences]
*/
- private val sPref by lazy {
- try {
+ private val sPref
+ get() = try {
context?.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)
?: error("If you want to use module prefs,you must set the context instance first")
} catch (_: Throwable) {
context?.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
?: error("If you want to use module prefs,you must set the context instance first")
}
- }
/** 设置全局可读可写 */
private fun makeWorldReadable() = runCatching {
@@ -112,6 +110,16 @@ class YukiHookModulePrefs(private val context: Context? = null) {
}
}
+ /**
+ * 自定义 Sp 存储名称
+ * @param name 自定义的 Sp 存储名称
+ * @return [YukiHookModulePrefs]
+ */
+ fun name(name: String): YukiHookModulePrefs {
+ prefsName = name
+ return this
+ }
+
/**
* 获取 [String] 键值
*