diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
index c3c7d9b8..96f0a6ac 100644
--- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
+++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
@@ -60,7 +60,7 @@ const val API_VERSION_CODE: Int
`v1.0.91` `removed`
-请转移到 `Status.executorName`
+请转移到 `Status.Executor.name`
executorVersion - field
@@ -70,7 +70,7 @@ const val API_VERSION_CODE: Int
`v1.0.91` `removed`
-请转移到 `Status.executorVersion`
+请转移到 `Status.Executor.apiLevel`、`Status.Executor.versionName`、`Status.Executor.versionCode`
## Status - object
@@ -114,49 +114,25 @@ val isXposedEnvironment: Boolean
> 获取当前是否为 (Xposed) 宿主环境。
-### executorName - field
-
-```kotlin:no-line-numbers
-val executorName: String
-```
+executorName - field
**Change Records**
`v1.0.91` `added`
-**Function Illustrate**
+`v1.1.5` `deprecated`
-> 获取当前 Hook 框架的名称。
+请转移到 `Executor.name`
-无法获取会返回 `unknown`,`XposedBridge` 不存在会返回 `invalid`。
-
-::: warning
-
-在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
-
-:::
-
-### executorVersion - field
-
-```kotlin:no-line-numbers
-val executorVersion: Int
-```
+executorVersion - field
**Change Records**
`v1.0.91` `added`
-**Function Illustrate**
+`v1.1.5` `deprecated`
-> 获取当前 Hook 框架的版本。
-
-无法获取会返回 `-1`。
-
-::: warning
-
-在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
-
-:::
+请转移到 `Executor.apiLevel`、`Executor.versionName`、`Executor.versionCode`
### isModuleActive - field
@@ -250,6 +226,100 @@ val isSupportResourcesHook: Boolean
:::
+### Executor - object
+
+```kotlin:no-line-numbers
+object Executor
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
+**Function Illustrate**
+
+> 当前 `YukiHookAPI` 使用的 Hook 框架相关信息。
+
+#### name - field
+
+```kotlin:no-line-numbers
+val name: String
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
+**Function Illustrate**
+
+> 获取当前 Hook 框架的名称。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### apiLevel - field
+
+```kotlin:no-line-numbers
+val apiLevel: Int
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
+**Function Illustrate**
+
+> 获取当前 Hook 框架的 API 版本。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### versionName - field
+
+```kotlin:no-line-numbers
+val versionName: String
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
+**Function Illustrate**
+
+> 获取当前 Hook 框架的版本名称。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### versionCode - field
+
+```kotlin:no-line-numbers
+val versionCode: Int
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
+**Function Illustrate**
+
+> 获取当前 Hook 框架的版本号。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
## Configs - object
```kotlin:no-line-numbers
diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
index 609b0ca7..498aaed7 100644
--- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
+++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
@@ -18,7 +18,7 @@ You can use the **Chrome Translation Plugin** to translate entire pages for refe
**Function Illustrate**
-> 这是 `YukiHookAPI` 的日志封装类,可实现同时向 `Logcat` 和 `XposedBridge.log` 打印日志的功能。
+> 这是 `YukiHookAPI` 的日志封装类,可实现同时向 `Logcat` 和 (Xposed) 宿主环境打印日志的功能。
## LoggerType - class
@@ -50,19 +50,29 @@ LOGD
> 仅使用 `android.util.Log`。
-### XPOSEDBRIDGE - enum
-
-```kotlin:no-line-numbers
-XPOSEDBRIDGE
-```
+XPOSEDBRIDGE - enum
**Change Records**
`v1.1.0` `added`
+`v1.1.5` `deprecated`
+
+请转移到 `XPOSED_ENVIRONMENT`
+
+### XPOSED_ENVIRONMENT - enum
+
+```kotlin:no-line-numbers
+XPOSED_ENVIRONMENT
+```
+
+**Change Records**
+
+`v1.1.5` `added`
+
**Function Illustrate**
-> 仅使用 `XposedBridge.log`。
+> 仅在 (Xposed) 宿主环境使用。
::: danger
@@ -84,7 +94,7 @@ SCOPE
> 分区使用。
-(Xposed) 宿主环境仅使用 `XPOSEDBRIDGE`。
+(Xposed) 宿主环境仅使用 `XPOSED_ENVIRONMENT`。
模块环境仅使用 `LOGD`。
@@ -102,7 +112,7 @@ BOTH
> 同时使用。
-(Xposed) 宿主环境使用 `LOGD` 与 `XPOSEDBRIDGE`。
+(Xposed) 宿主环境使用 `LOGD` 与 `XPOSED_ENVIRONMENT`。
模块环境仅使用 `LOGD`。
@@ -415,7 +425,7 @@ fun elements(vararg item: Int)
> 自定义调试日志对外显示的元素。
-只对日志记录和 `XposedBridge.log` 生效。
+只对日志记录和 (Xposed) 宿主环境的日志生效。
日志元素的排列将按照你在 `item` 中设置的顺序进行显示。
@@ -473,7 +483,7 @@ fun loggerD(tag: String, msg: String, type: LoggerType)
**Function Illustrate**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `D`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `D`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -493,7 +503,7 @@ fun loggerI(tag: String, msg: String, type: LoggerType)
**Function Illustrate**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `I`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `I`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -513,7 +523,7 @@ fun loggerW(tag: String, msg: String, type: LoggerType)
**Function Illustrate**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `W`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `W`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -533,6 +543,6 @@ fun loggerE(tag: String, msg: String, e: Throwable?, type: LoggerType)
**Function Illustrate**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `E`,可携带 `e` 异常信息,将打印异常堆栈。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `E`,可携带 `e` 异常信息,将打印异常堆栈。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
\ No newline at end of file
diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
index c10bd281..30517fe0 100644
--- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
+++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md
@@ -52,7 +52,7 @@ const val API_VERSION_CODE: Int
`v1.0.91` `移除`
-请转移到 `Status.executorName`
+请转移到 `Status.Executor.name`
executorVersion - field
@@ -62,7 +62,7 @@ const val API_VERSION_CODE: Int
`v1.0.91` `移除`
-请转移到 `Status.executorVersion`
+请转移到 `Status.Executor.apiLevel`、`Status.Executor.versionName`、`Status.Executor.versionCode`
## Status - object
@@ -106,49 +106,25 @@ val isXposedEnvironment: Boolean
> 获取当前是否为 (Xposed) 宿主环境。
-### executorName - field
-
-```kotlin:no-line-numbers
-val executorName: String
-```
+executorName - field
**变更记录**
`v1.0.91` `新增`
-**功能描述**
+`v1.1.5` `作废`
-> 获取当前 Hook 框架的名称。
+请转移到 `Executor.name`
-无法获取会返回 `unknown`,`XposedBridge` 不存在会返回 `invalid`。
-
-::: warning
-
-在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
-
-:::
-
-### executorVersion - field
-
-```kotlin:no-line-numbers
-val executorVersion: Int
-```
+executorVersion - field
**变更记录**
`v1.0.91` `新增`
-**功能描述**
+`v1.1.5` `作废`
-> 获取当前 Hook 框架的版本。
-
-无法获取会返回 `-1`。
-
-::: warning
-
-在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
-
-:::
+请转移到 `Executor.apiLevel`、`Executor.versionName`、`Executor.versionCode`
### isModuleActive - field
@@ -242,6 +218,100 @@ val isSupportResourcesHook: Boolean
:::
+### Executor - object
+
+```kotlin:no-line-numbers
+object Executor
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
+**功能描述**
+
+> 当前 `YukiHookAPI` 使用的 Hook 框架相关信息。
+
+#### name - field
+
+```kotlin:no-line-numbers
+val name: String
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
+**功能描述**
+
+> 获取当前 Hook 框架的名称。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### apiLevel - field
+
+```kotlin:no-line-numbers
+val apiLevel: Int
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
+**功能描述**
+
+> 获取当前 Hook 框架的 API 版本。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### versionName - field
+
+```kotlin:no-line-numbers
+val versionName: String
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
+**功能描述**
+
+> 获取当前 Hook 框架的版本名称。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
+#### versionCode - field
+
+```kotlin:no-line-numbers
+val versionCode: Int
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
+**功能描述**
+
+> 获取当前 Hook 框架的版本号。
+
+::: warning
+
+在模块环境中需要启用 **Configs.isEnableHookModuleStatus**。
+
+:::
+
## Configs - object
```kotlin:no-line-numbers
diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
index 8c2eb1f0..461f9ac2 100644
--- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
+++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/LoggerFactory.md
@@ -10,7 +10,7 @@ pageClass: code-page
**功能描述**
-> 这是 `YukiHookAPI` 的日志封装类,可实现同时向 `Logcat` 和 `XposedBridge.log` 打印日志的功能。
+> 这是 `YukiHookAPI` 的日志封装类,可实现同时向 `Logcat` 和 (Xposed) 宿主环境打印日志的功能。
## LoggerType - class
@@ -42,19 +42,29 @@ LOGD
> 仅使用 `android.util.Log`。
-### XPOSEDBRIDGE - enum
-
-```kotlin:no-line-numbers
-XPOSEDBRIDGE
-```
+XPOSEDBRIDGE - enum
**变更记录**
`v1.1.0` `新增`
+`v1.1.5` `作废`
+
+请转移到 `XPOSED_ENVIRONMENT`
+
+### XPOSED_ENVIRONMENT - enum
+
+```kotlin:no-line-numbers
+XPOSED_ENVIRONMENT
+```
+
+**变更记录**
+
+`v1.1.5` `新增`
+
**功能描述**
-> 仅使用 `XposedBridge.log`。
+> 仅在 (Xposed) 宿主环境使用。
::: danger
@@ -76,7 +86,7 @@ SCOPE
> 分区使用。
-(Xposed) 宿主环境仅使用 `XPOSEDBRIDGE`。
+(Xposed) 宿主环境仅使用 `XPOSED_ENVIRONMENT`。
模块环境仅使用 `LOGD`。
@@ -94,7 +104,7 @@ BOTH
> 同时使用。
-(Xposed) 宿主环境使用 `LOGD` 与 `XPOSEDBRIDGE`。
+(Xposed) 宿主环境使用 `LOGD` 与 `XPOSED_ENVIRONMENT`。
模块环境仅使用 `LOGD`。
@@ -407,7 +417,7 @@ fun elements(vararg item: Int)
> 自定义调试日志对外显示的元素。
-只对日志记录和 `XposedBridge.log` 生效。
+只对日志记录和 (Xposed) 宿主环境的日志生效。
日志元素的排列将按照你在 `item` 中设置的顺序进行显示。
@@ -465,7 +475,7 @@ fun loggerD(tag: String, msg: String, type: LoggerType)
**功能描述**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `D`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `D`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -485,7 +495,7 @@ fun loggerI(tag: String, msg: String, type: LoggerType)
**功能描述**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `I`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `I`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -505,7 +515,7 @@ fun loggerW(tag: String, msg: String, type: LoggerType)
**功能描述**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `W`。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `W`。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
@@ -525,6 +535,6 @@ fun loggerE(tag: String, msg: String, e: Throwable?, type: LoggerType)
**功能描述**
-> 向 `Logcat` 和 `XposedBridge` 打印日志,级别 `E`,可携带 `e` 异常信息,将打印异常堆栈。
+> 向 `Logcat` 和 (Xposed) 宿主环境打印日志,级别 `E`,可携带 `e` 异常信息,将打印异常堆栈。
`tag` 的默认参数为 `YukiHookAPI.Configs.debugTag`,你可以进行自定义。
\ No newline at end of file
diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt
index 25612577..327bc34b 100644
--- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt
+++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt
@@ -251,23 +251,23 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
msg = "You set the customize module package name to \"${data.customMPackageName}\", " +
"please check for yourself if it is correct"
)
+ /** 插入 YukiHookAPI_Impl 代码 */
+ createCodeFile(
+ fileName = ClassName.YukiHookAPI_Impl,
+ packageName = PackageName.YukiHookAPI_Impl,
+ content = data.sources()[ClassName.YukiHookAPI_Impl]
+ )
/** 插入 ModuleApplication_Impl 代码 */
createCodeFile(
fileName = ClassName.ModuleApplication_Impl,
packageName = PackageName.ModuleApplication_Impl,
content = data.sources()[ClassName.ModuleApplication_Impl]
)
- /** 插入 YukiHookBridge_Impl 代码 */
+ /** 插入 YukiXposedModuleStatus_Impl 代码 */
createCodeFile(
- fileName = ClassName.YukiHookBridge_Impl,
- packageName = PackageName.YukiHookBridge_Impl,
- content = data.sources()[ClassName.YukiHookBridge_Impl]
- )
- /** 插入 YukiHookModuleStatus_Impl 代码 */
- createCodeFile(
- fileName = ClassName.YukiHookModuleStatus_Impl,
- packageName = PackageName.YukiHookModuleStatus_Impl,
- content = data.sources()[ClassName.YukiHookModuleStatus_Impl]
+ fileName = ClassName.YukiXposedModuleStatus_Impl,
+ packageName = PackageName.YukiXposedModuleStatus_Impl,
+ content = data.sources()[ClassName.YukiXposedModuleStatus_Impl]
)
/** 插入 xposed_init 代码 */
createCodeFile(
diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt
index 1fee751c..03d3b74b 100644
--- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt
+++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt
@@ -35,9 +35,9 @@ import java.util.*
* 包名常量定义类
*/
object PackageName {
+ const val YukiHookAPI_Impl = "com.highcapable.yukihookapi"
const val ModuleApplication_Impl = "com.highcapable.yukihookapi.hook.xposed.application"
- const val YukiHookBridge_Impl = "com.highcapable.yukihookapi.hook.xposed.bridge"
- const val YukiHookModuleStatus_Impl = "com.highcapable.yukihookapi.hook.xposed.bridge.status"
+ const val YukiXposedModuleStatus_Impl = "com.highcapable.yukihookapi.hook.xposed.bridge.status"
const val BootstrapReflectionClass = "com.highcapable.yukihookapi.thirdparty.me.weishu.reflection"
}
@@ -45,9 +45,9 @@ object PackageName {
* 类名常量定义类
*/
object ClassName {
+ const val YukiHookAPI_Impl = "YukiHookAPI_Impl"
const val ModuleApplication_Impl = "ModuleApplication_Impl"
- const val YukiHookBridge_Impl = "YukiHookBridge_Impl"
- const val YukiHookModuleStatus_Impl = "YukiHookModuleStatus_Impl"
+ const val YukiXposedModuleStatus_Impl = "YukiXposedModuleStatus_Impl"
const val XposedInit = "xposed_init"
const val XposedInit_Impl = "xposed_init_Impl"
const val BootstrapClass = "BootstrapClass"
@@ -55,13 +55,15 @@ object ClassName {
}
/**
- * YukiHookModuleStatus 方法名称定义类
+ * YukiXposedModuleStatus 方法名称定义类
*/
-object YukiHookModuleStatusJvmName {
+object YukiXposedModuleStatusJvmName {
const val IS_ACTIVE_METHOD_NAME = "__--"
const val IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME = "_--_"
- const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
- const val GET_XPOSED_TAG_METHOD_NAME = "_-_-"
+ const val GET_EXECUTOR_NAME_METHOD_NAME = "_-_-"
+ const val GET_EXECUTOR_API_LEVEL_METHOD_NAME = "-__-"
+ const val GET_EXECUTOR_VERSION_NAME_METHOD_NAME = "-_-_"
+ const val GET_EXECUTOR_VERSION_CODE_METHOD_NAME = "___-"
}
/**
@@ -89,6 +91,15 @@ private fun createCommentContent(entryClassName: String = "", currrentClassTag:
* @return [Map]<[String],[String]>
*/
fun GenerateData.sources() = mapOf(
+ ClassName.YukiHookAPI_Impl to ("@file:Suppress(\"ClassName\")\n" +
+ "\n" +
+ "package ${PackageName.YukiHookAPI_Impl}\n" +
+ "\n" +
+ createCommentContent(currrentClassTag = ClassName.YukiHookAPI_Impl) +
+ "object ${ClassName.YukiHookAPI_Impl} {\n" +
+ "\n" +
+ " val compiledTimestamp get() = ${System.currentTimeMillis()}\n" +
+ "}"),
ClassName.ModuleApplication_Impl to ("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package ${PackageName.ModuleApplication_Impl}\n" +
@@ -103,52 +114,56 @@ fun GenerateData.sources() = mapOf(
" } catch (_: Throwable) {\n" +
" }\n" +
"}"),
- ClassName.YukiHookBridge_Impl to ("@file:Suppress(\"ClassName\")\n" +
+ ClassName.YukiXposedModuleStatus_Impl to ("@file:Suppress(\"ClassName\")\n" +
"\n" +
- "package ${PackageName.YukiHookBridge_Impl}\n" +
- "\n" +
- createCommentContent(currrentClassTag = ClassName.YukiHookBridge_Impl) +
- "object ${ClassName.YukiHookBridge_Impl} {\n" +
- "\n" +
- " val compiledTimestamp get() = ${System.currentTimeMillis()}\n" +
- "}"),
- ClassName.YukiHookModuleStatus_Impl to ("@file:Suppress(\"ClassName\")\n" +
- "\n" +
- "package com.highcapable.yukihookapi.hook.xposed.bridge.status\n" +
+ "package ${PackageName.YukiXposedModuleStatus_Impl}\n" +
"\n" +
"import android.util.Log\n" +
"import androidx.annotation.Keep\n" +
"\n" +
- createCommentContent(currrentClassTag = ClassName.YukiHookModuleStatus_Impl) +
+ createCommentContent(currrentClassTag = ClassName.YukiXposedModuleStatus_Impl) +
"@Keep\n" +
- "object YukiHookModuleStatus_Impl {\n" +
+ "object ${ClassName.YukiXposedModuleStatus_Impl} {\n" +
"\n" +
- " @JvmName(\"${YukiHookModuleStatusJvmName.IS_ACTIVE_METHOD_NAME}\")\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.IS_ACTIVE_METHOD_NAME}\")\n" +
" fun isActive(): Boolean {\n" +
" placeholderExecution()\n" +
" return false\n" +
" }\n" +
"\n" +
- " @JvmName(\"${YukiHookModuleStatusJvmName.IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME}\")\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME}\")\n" +
" fun isSupportResourcesHook(): Boolean {\n" +
" placeholderExecution()\n" +
" return false\n" +
" }\n" +
"\n" +
- " @JvmName(\"${YukiHookModuleStatusJvmName.GET_XPOSED_VERSION_METHOD_NAME}\")\n" +
- " fun getXposedVersion(): Int {\n" +
- " placeholderExecution()\n" +
- " return -1\n" +
- " }\n" +
- "\n" +
- " @JvmName(\"${YukiHookModuleStatusJvmName.GET_XPOSED_TAG_METHOD_NAME}\")\n" +
- " fun getXposedBridgeTag(): String {\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.GET_EXECUTOR_NAME_METHOD_NAME}\")\n" +
+ " fun getExecutorName(): String {\n" +
" placeholderExecution()\n" +
" return \"unknown\"\n" +
" }\n" +
"\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.GET_EXECUTOR_API_LEVEL_METHOD_NAME}\")\n" +
+ " fun getExecutorApiLevel(): Int {\n" +
+ " placeholderExecution()\n" +
+ " return -1\n" +
+ " }\n" +
+ "\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.GET_EXECUTOR_VERSION_NAME_METHOD_NAME}\")\n" +
+ " fun getExecutorVersionName(): String {\n" +
+ " placeholderExecution()\n" +
+ " return \"unknown\"\n" +
+ " }\n" +
+ "\n" +
+ " @JvmName(\"${YukiXposedModuleStatusJvmName.GET_EXECUTOR_VERSION_CODE_METHOD_NAME}\")\n" +
+ " fun getExecutorVersionCode(): Int {\n" +
+ " placeholderExecution()\n" +
+ " return -1\n" +
+ " }\n" +
+ "\n" +
" private fun placeholderExecution() {\n" +
- " Log.d(\"YukiHookAPI-Placeholder\", \"No trace of hook in this time\")\n" +
+ " /** Consume a long method body */\n" +
+ " if (System.currentTimeMillis() == 0L) Log.d(\"${(1000..9999).random()}\", \"${(100000..999999).random()}\")\n" +
" }\n" +
"}"),
ClassName.XposedInit to ("@file:Suppress(\"ClassName\")\n" +
@@ -156,7 +171,7 @@ fun GenerateData.sources() = mapOf(
"package $entryPackageName\n" +
"\n" +
"import androidx.annotation.Keep\n" +
- "import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" +
+ "import com.highcapable.yukihookapi.hook.xposed.bridge.event.caller.YukiXposedEventCaller\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
(if (isUsingResourcesHook) "import de.robv.android.xposed.IXposedHookInitPackageResources\n" else "") +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" +
@@ -172,17 +187,17 @@ fun GenerateData.sources() = mapOf(
"\n" +
" override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" +
" ${entryClassName}_Impl.callInitZygote(sparam)\n" +
- " YukiXposedEvent.EventHandler.callInitZygote(sparam)\n" +
+ " YukiXposedEventCaller.callInitZygote(sparam)\n" +
" }\n" +
"\n" +
" override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" +
- " YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" +
+ " YukiXposedEventCaller.callHandleLoadPackage(lpparam)\n" +
" }\n" +
(if (isUsingResourcesHook)
("\n override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" +
" ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" +
- " YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" +
+ " YukiXposedEventCaller.callHandleInitPackageResources(resparam)\n" +
" }\n") else "") +
"}"),
ClassName.XposedInit_Impl to ("@file:Suppress(\"ClassName\")\n" +
@@ -190,9 +205,11 @@ fun GenerateData.sources() = mapOf(
"package $entryPackageName\n" +
"\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
- "import com.highcapable.yukihookapi.hook.log.loggerE\n" +
- "import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge\n" +
+ "import com.highcapable.yukihookapi.hook.xposed.bridge.caller.YukiXposedModuleCaller\n" +
+ "import com.highcapable.yukihookapi.hook.xposed.bridge.resources.caller.YukiXposedResourcesCaller\n" +
+ "import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType\n" +
"import de.robv.android.xposed.IXposedHookZygoteInit\n" +
+ "import de.robv.android.xposed.XposedBridge\n" +
"import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
(if (customMPackageName.isBlank()) "import $modulePackageName.BuildConfig\n" else "") +
@@ -203,48 +220,54 @@ fun GenerateData.sources() = mapOf(
"\n" +
" private const val modulePackageName = " +
(if (customMPackageName.isNotBlank()) "\"$customMPackageName\"" else "BuildConfig.APPLICATION_ID") + "\n" +
- "\n" +
- " private var isZygoteBinded = false\n" +
- "\n" +
+ " private var isZygoteCalled = false\n" +
" private val hookEntry = " + (if (isEntryClassKindOfObject) "$entryClassName\n" else "$entryClassName()\n") +
"\n" +
- " private fun callXposedLoaded(\n" +
+ " private fun callOnXposedModuleLoaded(\n" +
" isZygoteLoaded: Boolean = false,\n" +
" lpparam: XC_LoadPackage.LoadPackageParam? = null,\n" +
" resparam: XC_InitPackageResources.InitPackageResourcesParam? = null\n" +
" ) {\n" +
- " if (isZygoteBinded.not()) runCatching {\n" +
+ " if (isZygoteCalled.not()) runCatching {\n" +
" hookEntry.onXposedEvent()\n" +
" hookEntry.onInit()\n" +
- " if (YukiHookBridge.isXposedCallbackSetUp) {\n" +
- " loggerE(msg = \"You cannot load a hooker in \\\"onInit\\\" or \\\"onXposedEvent\\\" method! Aborted\")\n" +
+ " if (YukiXposedModuleCaller.isXposedCallbackSetUp) {\n" +
+ " YukiXposedModuleCaller.internalLoggerE(\"You cannot load a hooker in \\\"onInit\\\" or \\\"onXposedEvent\\\" method! Aborted\")\n" +
" return\n" +
" }\n" +
" hookEntry.onHook()\n" +
- " YukiHookBridge.callXposedInitialized()\n" +
- " YukiHookBridge.modulePackageName = modulePackageName\n" +
- " }.onFailure { loggerE(msg = \"YukiHookAPI try to load HookEntryClass failed\", e = it) }\n" +
- " YukiHookBridge.callXposedLoaded(isZygoteLoaded, lpparam, resparam)\n" +
+ " YukiXposedModuleCaller.callOnFinishLoadModule()\n" +
+ " }.onFailure { YukiXposedModuleCaller.internalLoggerE(\"YukiHookAPI try to load HookEntryClass failed\", it) }\n" +
+ " YukiXposedModuleCaller.callOnPackageLoaded(\n" +
+ " type = when {\n" +
+ " isZygoteLoaded -> HookEntryType.ZYGOTE\n" +
+ " lpparam != null -> HookEntryType.PACKAGE\n" +
+ " resparam != null -> HookEntryType.RESOURCES\n" +
+ " else -> HookEntryType.ZYGOTE\n" +
+ " },\n" +
+ " packageName = lpparam?.packageName ?: resparam?.packageName,\n" +
+ " processName = lpparam?.processName,\n" +
+ " appClassLoader = lpparam?.classLoader ?: runCatching { XposedBridge.BOOTCLASSLOADER }.getOrNull(),\n" +
+ " appInfo = lpparam?.appInfo,\n" +
+ " appResources = YukiXposedResourcesCaller.createYukiResourcesFromXResources(resparam?.res)\n" +
+ " )\n" +
" }\n" +
"\n" +
- " @YukiGenerateApi\n" +
" fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" +
" if (sparam == null) return\n" +
" runCatching {\n" +
- " YukiHookBridge.callXposedZygoteLoaded(sparam)\n" +
- " }.onFailure { loggerE(msg = \"YukiHookAPI bind initZygote failed\", e = it) }\n" +
- " callXposedLoaded(isZygoteLoaded = true)\n" +
- " isZygoteBinded = true\n" +
+ " YukiXposedModuleCaller.callOnStartLoadModule(modulePackageName, sparam.modulePath)\n" +
+ " callOnXposedModuleLoaded(isZygoteLoaded = true)\n" +
+ " isZygoteCalled = true\n" +
+ " }.onFailure { YukiXposedModuleCaller.internalLoggerE(\"An exception occurred when YukiHookAPI loading Xposed Module\", it) }\n" +
" }\n" +
"\n" +
- " @YukiGenerateApi\n" +
" fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
- " if (lpparam != null) callXposedLoaded(lpparam = lpparam)\n" +
+ " if (lpparam != null && isZygoteCalled) callOnXposedModuleLoaded(lpparam = lpparam)\n" +
" }\n" +
"\n" +
- " @YukiGenerateApi\n" +
" fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" +
- " if (resparam != null) callXposedLoaded(resparam = resparam)\n" +
+ " if (resparam != null && isZygoteCalled) callOnXposedModuleLoaded(resparam = resparam)\n" +
" }\n" +
"}"),
ClassName.BootstrapClass to ("package ${PackageName.BootstrapReflectionClass};\n" +
@@ -263,7 +286,6 @@ fun GenerateData.sources() = mapOf(
"public final class BootstrapClass {\n" +
"\n" +
" private static final String TAG = \"BootstrapClass\";\n" +
- "\n" +
" private static Object sVmRuntime;\n" +
" private static Method setHiddenApiExemptions;\n" +
"\n" +
@@ -290,7 +312,6 @@ fun GenerateData.sources() = mapOf(
" if (sVmRuntime == null || setHiddenApiExemptions == null) {\n" +
" return false;\n" +
" }\n" +
- "\n" +
" try {\n" +
" setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});\n" +
" return true;\n" +
@@ -323,8 +344,8 @@ fun GenerateData.sources() = mapOf(
createCommentContent(currrentClassTag = ClassName.Reflection) +
"@Keep\n" +
"public class Reflection {\n" +
- " private static final String TAG = \"Reflection\";\n" +
"\n" +
+ " private static final String TAG = \"Reflection\";\n" +
" private static final String DEX = \"ZGV4CjAzNQCXDT0vQ44GJqsrjm32y0qlQmxUevbk56r0CwAAcAAAAHhWNBIAAAAAAAAAADwLAABDAAAAcAAAABMAAAB8AQAACwAAAMgBAAAMAAAATAIAAA8AAACsAgAAAwAAACQDAABwCAAAhAMAAIQDAACGAwAAiwMAAJUDAACdAwAArQMAALkDAADJAwAA3gMAAPADAAD3AwAA/wMAAAIEAAAGBAAACgQAABAEAAATBAAAGAQAADMEAABZBAAAdQQAAIkEAADYBAAAJgUAAHAFAACDBQAAmQUAAK0FAADBBQAA1QUAAOwFAAAIBgAAFAYAACUGAAAuBgAAMwYAADYGAABEBgAAUgYAAFYGAABZBgAAXQYAAHEGAACGBgAAmwYAAKQGAAC9BgAAwAYAAMgGAADTBgAA3AYAAO0GAAABBwAAFAcAACAHAAAoBwAANQcAAE8HAABXBwAAYAcAAHsHAACEBwAAkAcAAKgHAAC6BwAAwgcAANAHAAALAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAaAAAAGwAAABwAAAAdAAAAHgAAACMAAAAnAAAAKQAAACoAAAArAAAADAAAAAAAAAD4BwAADQAAAAAAAAAMCAAADgAAAAAAAAAACAAADwAAAAIAAAAAAAAAEAAAAAkAAAAUCAAAEAAAAA0AAADoBwAAIwAAAA4AAAAAAAAAJgAAAA4AAADgBwAAJwAAAA8AAAAAAAAAKAAAAA8AAADgBwAAKAAAAA8AAADwBwAAAgAAAD8AAAADAAAAIQAAAAUACgAEAAAABQAKAAUAAAAFAA8ACQAAAAUACgAKAAAABQAAACQAAAAFAAoAJQAAAAYACgAiAAAABgAJAD0AAAAGAA0APgAAAAcACgAiAAAAAQADADMAAAAEAAIALgAAAAUABgADAAAABgAGAAIAAAAGAAYAAwAAAAYACQAvAAAABgAKAC8AAAAGAAgAMAAAAAcABgADAAAABwABAEAAAAAHAAAAQQAAAAgABQA0AAAACQAGAAMAAAALAAcANwAAAA0ABAA2AAAABQAAABEAAAAJAAAAAAAAAAgAAAAAAAAA7AoAAB8IAAAGAAAAEQAAAAkAAAAAAAAABwAAAAAAAAACCwAAHAgAAAcAAAABAAAACQAAAAAAAAAgAAAAAAAAACULAAArCAAAAAADMS4wAAg8Y2xpbml0PgAGPGluaXQ+AA5BUFBMSUNBVElPTl9JRAAKQlVJTERfVFlQRQAOQm9vdHN0cmFwQ2xhc3MAE0Jvb3RzdHJhcENsYXNzLmphdmEAEEJ1aWxkQ29uZmlnLmphdmEABURFQlVHAAZGTEFWT1IAAUkAAklJAAJJTAAESUxMTAABTAADTExMABlMYW5kcm9pZC9jb250ZW50L0NvbnRleHQ7ACRMYW5kcm9pZC9jb250ZW50L3BtL0FwcGxpY2F0aW9uSW5mbzsAGkxhbmRyb2lkL29zL0J1aWxkJFZFUlNJT047ABJMYW5kcm9pZC91dGlsL0xvZzsATUxjb20vaGlnaGNhcGFibGUveXVraWhvb2thcGkvdGhpcmRwYXJ0eS9tZS93ZWlzaHUvZnJlZXJlZmxlY3Rpb24vQnVpbGRDb25maWc7AExMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vQm9vdHN0cmFwQ2xhc3M7AEhMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vUmVmbGVjdGlvbjsAEUxqYXZhL2xhbmcvQ2xhc3M7ABRMamF2YS9sYW5nL0NsYXNzPCo+OwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwAKUmVmbGVjdGlvbgAPUmVmbGVjdGlvbi5qYXZhAAdTREtfSU5UAANUQUcAAVYADFZFUlNJT05fQ09ERQAMVkVSU0lPTl9OQU1FAAJWTAABWgACWkwAEltMamF2YS9sYW5nL0NsYXNzOwATW0xqYXZhL2xhbmcvT2JqZWN0OwATW0xqYXZhL2xhbmcvU3RyaW5nOwAHY29udGV4dAAXZGFsdmlrLnN5c3RlbS5WTVJ1bnRpbWUAAWUABmV4ZW1wdAAJZXhlbXB0QWxsAAdmb3JOYW1lAA9mcmVlLXJlZmxlY3Rpb24AEmdldEFwcGxpY2F0aW9uSW5mbwARZ2V0RGVjbGFyZWRNZXRob2QACmdldFJ1bnRpbWUABmludm9rZQALbG9hZExpYnJhcnkAGG1lLndlaXNodS5mcmVlcmVmbGVjdGlvbgAGbWV0aG9kAAdtZXRob2RzABlyZWZsZWN0IGJvb3RzdHJhcCBmYWlsZWQ6AAdyZWxlYXNlAApzVm1SdW50aW1lABZzZXRIaWRkZW5BcGlFeGVtcHRpb25zABB0YXJnZXRTZGtWZXJzaW9uAAZ1bnNlYWwADHVuc2VhbE5hdGl2ZQAOdm1SdW50aW1lQ2xhc3MAAQAAAAoAAAACAAAACgAQAAEAAAASAAAAAQAAAAAAAAADAAAACgAKAAwAAAABAAAAAQAAAAIAAAAJABEAARcGBhc4FzwfFwAEARcBARcfAAAAAAAABgAHDgAWAAcOav8DATIOARUQAwI1DvAEBEMJGgESDwMDNg4BGw+pBQIFAwUEGR4DAC8NAA4ABw4ALAE6Bw4ANgE7ByydGuIBAQMALw0eAEgABw4ADQAHDgATAS0HHXIZa1oAAAEAAQABAAAANAgAAAQAAABwEAwAAAAOAAoAAAADAAEAOQgAAHsAAABgBQEAEwYcADRlbQAcBQgAGgYxABIXI3cQABIIHAkKAE0JBwhuMAsAZQcMARwFCAAaBjQAEicjdxAAEggcCQoATQkHCBIYHAkQAE0JBwhuMAsAZQcMAhIFEhYjZhEAEgcaCC0ATQgGB24wDgBRBgwEHwQIABIlI1URABIGGgc1AE0HBQYSFhIHTQcFBm4wDgBCBQwDHwMNABIlI1URABIGGgc+AE0HBQYSFhIXI3cQABIIHAkSAE0JBwhNBwUGbjAOAEIFDAUfBQ0AaQUKABIFEgYjZhEAbjAOAFMGDAVpBQkADgANABoFBgAaBjsAcTABAGUAKPcAAAYAAABrAAEAAQEMcgEAAQABAAAAaAgAAAQAAABwEAwAAAAOAAMAAQABAAAAbQgAAAsAAAASECMAEgASAU0CAAFxEAYAAAAKAA8AAAAIAAEAAwABAHMIAAAdAAAAEhESAmIDCQA4AwYAYgMKADkDBAABIQ8BYgMKAGIECQASFSNVEQASBk0HBQZuMA4AQwUo8g0AASEo7wAADAAAAA0AAQABAQwaAwAAAAEAAACDCAAADQAAABIQIwASABIBGgIPAE0CAAFxEAYAAAAKAA8AAAABAAEAAQAAAIgIAAAEAAAAcBAMAAAADgAEAAEAAQAAAI0IAAAeAAAAEgBgAQEAEwIcADUhAwAPAHEABwAAAAoBOQH7/xoAMgBxEA0AAABuEAAAAwAMAFIAAABxEAoAAAAKACjqBgABAAIZARkBGQEZARkBGQKBgASYEQMABQAIGgEKAQoDiIAEsBEBgYAExBMBCdwTAYkBhBQBCdwUAQADAAsaCIGABIgVAQmgFQGKAgAAAAAPAAAAAAAAAAEAAAAAAAAAAQAAAEMAAABwAAAAAgAAABMAAAB8AQAAAwAAAAsAAADIAQAABAAAAAwAAABMAgAABQAAAA8AAACsAgAABgAAAAMAAAAkAwAAAiAAAEMAAACEAwAAARAAAAcAAADgBwAABSAAAAMAAAAcCAAAAxAAAAEAAAAwCAAAAyAAAAgAAAA0CAAAASAAAAgAAACYCAAAACAAAAMAAADsCgAAABAAAAEAAAA8CwAA\";\n" +
"\n" +
" private static native int unsealNative(int targetSdkVersion);\n" +
@@ -334,7 +355,6 @@ fun GenerateData.sources() = mapOf(
" // Below Android P, ignore\n" +
" return 0;\n" +
" }\n" +
- "\n" +
" // try exempt API first.\n" +
" if (exemptAll()) {\n" +
" return 0;\n" +
@@ -342,7 +362,6 @@ fun GenerateData.sources() = mapOf(
" if (unsealByDexFile(context)) {\n" +
" return 0;\n" +
" }\n" +
- "\n" +
" return -1;\n" +
" }\n" +
"\n" +
@@ -355,11 +374,9 @@ fun GenerateData.sources() = mapOf(
" }\n" +
" File code = new File(codeCacheDir, \"__temp_\" + System.currentTimeMillis() + \".dex\");\n" +
" try {\n" +
- "\n" +
" try (FileOutputStream fos = new FileOutputStream(code)) {\n" +
" fos.write(bytes);\n" +
" }\n" +
- "\n" +
" DexFile dexFile = new DexFile(code);\n" +
" // This class is hardcoded in the dex, Don't use BootstrapClass.class to reference it\n" +
" // it maybe obfuscated!!\n" +
diff --git a/yukihookapi-stub/build.gradle b/yukihookapi-stub/build.gradle
index ff154fb9..cdb7fb5f 100644
--- a/yukihookapi-stub/build.gradle
+++ b/yukihookapi-stub/build.gradle
@@ -8,8 +8,17 @@ java {
targetCompatibility = JavaVersion.VERSION_11
}
+tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
+ kotlinOptions {
+ jvmTarget = 11
+ freeCompilerArgs = [
+ '-Xno-param-assertions',
+ '-Xno-call-assertions',
+ '-Xno-receiver-assertions'
+ ]
+ }
+}
+
dependencies {
- // Used 82 API Version
- compileOnly 'de.robv.android.xposed:api:82'
compileOnly fileTree(include: ['*.jar'], dir: '../yukihookapi/libs')
}
\ No newline at end of file
diff --git a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge_Impl.kt b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/YukiHookAPI_Impl.kt
similarity index 91%
rename from yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge_Impl.kt
rename to yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/YukiHookAPI_Impl.kt
index 6b0d6cb2..6bbfc9ce 100644
--- a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge_Impl.kt
+++ b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/YukiHookAPI_Impl.kt
@@ -24,15 +24,16 @@
* SOFTWARE.
*
* This file is Created by fankes on 2022/9/26.
+ * This file is Modified by fankes on 2023/1/9.
*/
@file:Suppress("ClassName")
-package com.highcapable.yukihookapi.hook.xposed.bridge
+package com.highcapable.yukihookapi
/**
- * YukiHookBridge 注入 Stub
+ * YukiHookAPI 注入 Stub
*/
-object YukiHookBridge_Impl {
+object YukiHookAPI_Impl {
/**
* 获取项目编译完成的时间戳 (当前本地时间)
diff --git a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus_Impl.kt
similarity index 64%
rename from yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt
rename to yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus_Impl.kt
index f87912ac..74bb794c 100644
--- a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt
+++ b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus_Impl.kt
@@ -24,29 +24,23 @@
* SOFTWARE.
*
* This file is Created by fankes on 2023/1/1.
+ * This file is Modified by fankes on 2023/1/9.
*/
@file:Suppress("ClassName")
package com.highcapable.yukihookapi.hook.xposed.bridge.status
-import de.robv.android.xposed.XposedBridge
-
/**
- * YukiHookModuleStatus 注入 Stub
+ * YukiXposedModuleStatus 注入 Stub
*/
-object YukiHookModuleStatus_Impl {
+object YukiXposedModuleStatus_Impl {
- /** 定义 Jvm 方法名 */
private const val IS_ACTIVE_METHOD_NAME = "__--"
-
- /** 定义 Jvm 方法名 */
private const val IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME = "_--_"
-
- /** 定义 Jvm 方法名 */
- private const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
-
- /** 定义 Jvm 方法名 */
- private const val GET_XPOSED_TAG_METHOD_NAME = "_-_-"
+ private const val GET_EXECUTOR_NAME_METHOD_NAME = "_-_-"
+ private const val GET_EXECUTOR_API_LEVEL_METHOD_NAME = "-__-"
+ private const val GET_EXECUTOR_VERSION_NAME_METHOD_NAME = "-_-_"
+ private const val GET_EXECUTOR_VERSION_CODE_METHOD_NAME = "___-"
/**
* 此方法经过 Hook 后返回 true 即模块已激活
@@ -67,20 +61,38 @@ object YukiHookModuleStatus_Impl {
fun isSupportResourcesHook(): Boolean = error("Stub!")
/**
- * 此方法经过 Hook 后返回 [XposedBridge.getXposedVersion]
- *
- * 返回值将在每次编译时自动生成
- * @return [Int]
- */
- @JvmName(GET_XPOSED_VERSION_METHOD_NAME)
- fun getXposedVersion(): Int = error("Stub!")
-
- /**
- * 此方法经过 Hook 后返回 [XposedBridge] 的 TAG
+ * 此方法经过 Hook 后返回当前 Hook 框架的名称
*
* 返回值将在每次编译时自动生成
* @return [String]
*/
- @JvmName(GET_XPOSED_TAG_METHOD_NAME)
- fun getXposedBridgeTag(): String = error("Stub!")
+ @JvmName(GET_EXECUTOR_NAME_METHOD_NAME)
+ fun getExecutorName(): String = error("Stub!")
+
+ /**
+ * 此方法经过 Hook 后返回当前 Hook 框架的 API 版本
+ *
+ * 返回值将在每次编译时自动生成
+ * @return [Int]
+ */
+ @JvmName(GET_EXECUTOR_API_LEVEL_METHOD_NAME)
+ fun getExecutorApiLevel(): Int = error("Stub!")
+
+ /**
+ * 此方法经过 Hook 后返回当前 Hook 框架的版本名称
+ *
+ * 返回值将在每次编译时自动生成
+ * @return [String]
+ */
+ @JvmName(GET_EXECUTOR_VERSION_NAME_METHOD_NAME)
+ fun getExecutorVersionName(): String = error("Stub!")
+
+ /**
+ * 此方法经过 Hook 后返回当前 Hook 框架的版本号
+ *
+ * 返回值将在每次编译时自动生成
+ * @return [Int]
+ */
+ @JvmName(GET_EXECUTOR_VERSION_CODE_METHOD_NAME)
+ fun getExecutorVersionCode(): Int = error("Stub!")
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/YukiHookAPI.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/YukiHookAPI.kt
index 72206adf..08604082 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/YukiHookAPI.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/YukiHookAPI.kt
@@ -33,9 +33,12 @@ import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Resources
+import com.highcapable.yukihookapi.YukiHookAPI.Configs.debugLog
import com.highcapable.yukihookapi.YukiHookAPI.configs
import com.highcapable.yukihookapi.YukiHookAPI.encase
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiProperty
import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder
import com.highcapable.yukihookapi.hook.core.finder.members.FieldFinder
import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
@@ -47,14 +50,13 @@ import com.highcapable.yukihookapi.hook.log.YukiHookLogger
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.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
+import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
-import de.robv.android.xposed.XposedBridge
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Member
@@ -65,7 +67,7 @@ import java.lang.reflect.Method
*
* 可以实现作为模块装载和自定义 Hook 装载两种方式
*
- * 模块装载方式已经自动对接 Xposed API - 可直接调用 [encase] 完成操作
+ * Xposed 模块装载方式已经自动对接相关 API - 可直接调用 [encase] 完成操作
*
* 你可以调用 [configs] 对 [YukiHookAPI] 进行配置
*/
@@ -92,38 +94,41 @@ object YukiHookAPI {
* 获取项目编译完成的时间戳 (当前本地时间)
* @return [Long]
*/
- val compiledTimestamp get() = YukiHookBridge.compiledTimestamp
+ val compiledTimestamp get() = runCatching { YukiHookAPI_Impl.compiledTimestamp }.getOrNull() ?: 0L
/**
* 获取当前是否为 (Xposed) 宿主环境
* @return [Boolean]
*/
- val isXposedEnvironment get() = YukiHookBridge.hasXposedBridge
+ val isXposedEnvironment get() = YukiXposedModule.isXposedEnvironment
/**
* 获取当前 Hook 框架的名称
*
- * 从 [XposedBridge] 获取 TAG
+ * - ❗此方法已弃用 - 在之后的版本中将直接被删除
*
- * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
- * @return [String] 无法获取会返回 unknown - [YukiHookBridge.hasXposedBridge] 不存在会返回 invalid
+ * - ❗请现在转移到 [Executor.name]
+ * @return [String]
*/
- val executorName
- get() = YukiHookBridge.executorName.takeIf { isXposedEnvironment } ?: when {
- isXposedModuleActive -> YukiHookModuleStatus.executorName
- isTaiChiModuleActive -> YukiHookModuleStatus.TAICHI_XPOSED_NAME
- else -> YukiHookModuleStatus.executorName
- }
+ @Deprecated(
+ message = "请使用新方式来实现此功能",
+ ReplaceWith("Executor.name", "com.highcapable.yukihookapi.YukiHookAPI.Status.Executor")
+ )
+ val executorName get() = Executor.name
/**
* 获取当前 Hook 框架的版本
*
- * 获取 [XposedBridge.getXposedVersion]
+ * - ❗此方法已弃用 - 在之后的版本中将直接被删除
*
- * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
- * @return [Int] 无法获取会返回 -1
+ * - ❗请现在转移到 [Executor.apiLevel]、[Executor.versionName]、[Executor.versionCode]
+ * @return [Int]
*/
- val executorVersion get() = YukiHookBridge.executorVersion.takeIf { isXposedEnvironment } ?: YukiHookModuleStatus.executorVersion
+ @Deprecated(
+ message = "请使用新方式来实现此功能",
+ ReplaceWith("Executor.apiLevel", "com.highcapable.yukihookapi.YukiHookAPI.Status.Executor")
+ )
+ val executorVersion get() = Executor.apiLevel
/**
* 判断模块是否在 Xposed 或太极、无极中激活
@@ -135,7 +140,7 @@ object YukiHookAPI {
* - ❗在 (Xposed) 宿主环境中仅返回非 [isTaiChiModuleActive] 的激活状态
* @return [Boolean] 是否激活
*/
- val isModuleActive get() = isXposedEnvironment || YukiHookModuleStatus.isActive || isTaiChiModuleActive
+ val isModuleActive get() = isXposedEnvironment || YukiXposedModuleStatus.isActive || isTaiChiModuleActive
/**
* 仅判断模块是否在 Xposed 中激活
@@ -145,7 +150,7 @@ object YukiHookAPI {
* - ❗在 (Xposed) 宿主环境中始终返回 true
* @return [Boolean] 是否激活
*/
- val isXposedModuleActive get() = isXposedEnvironment || YukiHookModuleStatus.isActive
+ val isXposedModuleActive get() = isXposedEnvironment || YukiXposedModuleStatus.isActive
/**
* 仅判断模块是否在太极、无极中激活
@@ -168,7 +173,50 @@ object YukiHookAPI {
* @return [Boolean] 是否支持
*/
val isSupportResourcesHook
- get() = YukiHookBridge.isSupportResourcesHook.takeIf { isXposedEnvironment } ?: YukiHookModuleStatus.isSupportResourcesHook
+ get() = YukiXposedModule.isSupportResourcesHook.takeIf { isXposedEnvironment } ?: YukiXposedModuleStatus.isSupportResourcesHook
+
+ /**
+ * 当前 [YukiHookAPI] 使用的 Hook 框架相关信息
+ */
+ object Executor {
+
+ /**
+ * 获取当前 Hook 框架的名称
+ *
+ * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
+ * @return [String] 无法获取会返回 unknown - 获取失败会返回 invalid
+ */
+ val name
+ get() = HookApiProperty.name.takeIf { isXposedEnvironment } ?: when {
+ isXposedModuleActive -> YukiXposedModuleStatus.executorName
+ isTaiChiModuleActive -> HookApiProperty.TAICHI_XPOSED_NAME
+ else -> YukiXposedModuleStatus.executorName
+ }
+
+ /**
+ * 获取当前 Hook 框架的 API 版本
+ *
+ * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
+ * @return [Int] 无法获取会返回 -1
+ */
+ val apiLevel get() = HookApiProperty.apiLevel.takeIf { isXposedEnvironment } ?: YukiXposedModuleStatus.executorApiLevel
+
+ /**
+ * 获取当前 Hook 框架的版本名称
+ *
+ * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
+ * @return [String] 无法获取会返回 unknown - 不支持会返回 unsupported
+ */
+ val versionName get() = HookApiProperty.versionName.takeIf { isXposedEnvironment } ?: YukiXposedModuleStatus.executorVersionName
+
+ /**
+ * 获取当前 Hook 框架的版本号
+ *
+ * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
+ * @return [Int] 无法获取会返回 -1 - 不支持会返回 0
+ */
+ val versionCode get() = HookApiProperty.versionCode.takeIf { isXposedEnvironment } ?: YukiXposedModuleStatus.executorVersionCode
+ }
}
/**
@@ -296,13 +344,6 @@ object YukiHookAPI {
internal fun build() = Unit
}
- /**
- * 装载 Xposed API 回调核心实现方法
- * @param wrapper 代理包装 [PackageParamWrapper]
- */
- internal fun onXposedLoaded(wrapper: PackageParamWrapper) =
- YukiHookBridge.packageParamCallback?.invoke(PackageParam(wrapper).apply { printSplashLog() })
-
/**
* 配置 [YukiHookAPI] 相关参数
*
@@ -314,7 +355,7 @@ object YukiHookAPI {
inline fun configs(initiate: Configs.() -> Unit) = Configs.apply(initiate).build()
/**
- * 作为模块装载调用入口方法 - Xposed API
+ * 作为 Xposed 模块装载调用入口方法
*
* 用法请参考 [API 文档](https://fankes.github.io/YukiHookAPI/zh-cn/api/home)
*
@@ -327,13 +368,13 @@ object YukiHookAPI {
*/
fun encase(initiate: PackageParam.() -> Unit) {
isLoadedFromBaseContext = false
- if (YukiHookBridge.hasXposedBridge)
- YukiHookBridge.packageParamCallback = initiate
- else printNoXposedEnvLog()
+ if (YukiXposedModule.isXposedEnvironment)
+ YukiXposedModule.packageParamCallback = initiate
+ else printNotFoundHookApiError()
}
/**
- * 作为模块装载调用入口方法 - Xposed API
+ * 作为 Xposed 模块装载调用入口方法
*
* 用法请参考 [API 文档](https://fankes.github.io/YukiHookAPI/zh-cn/api/home)
*
@@ -347,13 +388,13 @@ object YukiHookAPI {
*/
fun encase(vararg hooker: YukiBaseHooker) {
isLoadedFromBaseContext = false
- if (YukiHookBridge.hasXposedBridge)
- YukiHookBridge.packageParamCallback = {
+ if (YukiXposedModule.isXposedEnvironment)
+ YukiXposedModule.packageParamCallback = {
if (hooker.isNotEmpty())
hooker.forEach { it.assignInstance(packageParam = this) }
else yLoggerE(msg = "Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true)
}
- else printNoXposedEnvLog()
+ else printNotFoundHookApiError()
}
/**
@@ -378,8 +419,9 @@ object YukiHookAPI {
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit) {
isLoadedFromBaseContext = true
when {
- YukiHookBridge.hasXposedBridge && baseContext != null -> initiate(baseContext.packageParam.apply { printSplashLog() })
- else -> printNoXposedEnvLog()
+ HookApiCategoryHelper.hasAvailableHookApi && baseContext != null ->
+ initiate(baseContext.createPackageParam().apply { printSplashInfo() })
+ else -> printNotFoundHookApiError()
}
}
@@ -405,32 +447,33 @@ object YukiHookAPI {
*/
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker) {
isLoadedFromBaseContext = true
- if (YukiHookBridge.hasXposedBridge)
+ if (HookApiCategoryHelper.hasAvailableHookApi)
(if (baseContext != null)
if (hooker.isNotEmpty()) {
- printSplashLog()
- hooker.forEach { it.assignInstance(packageParam = baseContext.packageParam) }
+ printSplashInfo()
+ hooker.forEach { it.assignInstance(packageParam = baseContext.createPackageParam()) }
} else yLoggerE(msg = "Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true))
- else printNoXposedEnvLog()
+ else printNotFoundHookApiError()
}
/** 输出欢迎信息调试日志 */
- private fun printSplashLog() {
+ internal fun printSplashInfo() {
if (Configs.isDebug.not() || isShowSplashLogOnceTime.not()) return
isShowSplashLogOnceTime = false
yLoggerI(
- msg = "Welcome to YukiHookAPI $API_VERSION_NAME($API_VERSION_CODE)! Using ${Status.executorName} API ${Status.executorVersion}",
+ msg = "Welcome to YukiHookAPI $API_VERSION_NAME($API_VERSION_CODE)! Using ${Status.Executor.name} API ${Status.Executor.apiLevel}",
isImplicit = true
)
}
- /** 输出找不到 [XposedBridge] 的错误日志 */
- private fun printNoXposedEnvLog() = yLoggerE(msg = "Could not found XposedBridge in current space! Aborted", isImplicit = true)
+ /** 输出找不到 Hook API 的错误日志 */
+ private fun printNotFoundHookApiError() =
+ yLoggerE(msg = "Could not found any available Hook APIs in current environment! Aborted", isImplicit = true)
/**
* 通过 baseContext 创建 Hook 入口类
* @return [PackageParam]
*/
- private val Context.packageParam
- get() = PackageParam(PackageParamWrapper(HookEntryType.PACKAGE, packageName, processName, classLoader, applicationInfo))
+ private fun Context.createPackageParam() =
+ PackageParam(PackageParamWrapper(HookEntryType.PACKAGE, packageName, processName, classLoader, applicationInfo))
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookResources.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookResources.kt
index 649266aa..ef0fc508 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookResources.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookResources.kt
@@ -27,7 +27,7 @@
*/
package com.highcapable.yukihookapi.hook.bean
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
/**
* 创建一个当前 Hook 的 [YukiResources] 接管类
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.kt
index f71c2aac..84e632f4 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.kt
@@ -32,6 +32,12 @@ package com.highcapable.yukihookapi.hook.core
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.bean.HookClass
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
+import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
+import com.highcapable.yukihookapi.hook.core.api.priority.YukiHookPriority
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberReplacement
+import com.highcapable.yukihookapi.hook.core.api.result.YukiHookResult
import com.highcapable.yukihookapi.hook.core.finder.base.MemberBaseFinder
import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder
import com.highcapable.yukihookapi.hook.core.finder.members.FieldFinder
@@ -45,14 +51,9 @@ import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.log.yLoggerW
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.type.java.*
import com.highcapable.yukihookapi.hook.utils.await
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookPriority
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberReplacement
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Member
@@ -71,13 +72,13 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
) {
/** 默认 Hook 回调优先级 */
- val PRIORITY_DEFAULT = YukiHookPriority.PRIORITY_DEFAULT
+ val PRIORITY_DEFAULT = 0x0
/** 延迟回调 Hook 方法结果 */
- val PRIORITY_LOWEST = YukiHookPriority.PRIORITY_LOWEST
+ val PRIORITY_LOWEST = 0x1
/** 更快回调 Hook 方法结果 */
- val PRIORITY_HIGHEST = YukiHookPriority.PRIORITY_HIGHEST
+ val PRIORITY_HIGHEST = 0x2
/** Hook 操作选项内容 */
private var hookOption = ""
@@ -134,7 +135,7 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
*/
@PublishedApi
internal fun hook() = when {
- YukiHookBridge.hasXposedBridge.not() -> Result()
+ HookApiCategoryHelper.hasAvailableHookApi.not() -> Result()
/** 过滤 [HookEntryType.ZYGOTE] and [HookEntryType.PACKAGE] or [HookParam.isCallbackCalled] 已被执行 */
packageParam.wrapper?.type == HookEntryType.RESOURCES && HookParam.isCallbackCalled.not() -> Result()
preHookMembers.isEmpty() -> Result().also { yLoggerW(msg = "Hook Members is empty in [${hookClass.name}], hook aborted") }
@@ -192,6 +193,18 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
}
}
+ /**
+ * 转换到 [YukiHookPriority] 优先级
+ * @return [YukiHookPriority]
+ * @throws IllegalStateException 如果优先级不为 [PRIORITY_DEFAULT]、[PRIORITY_LOWEST]、[PRIORITY_HIGHEST]
+ */
+ private fun Int.toPriority() = when (this) {
+ PRIORITY_DEFAULT -> YukiHookPriority.DEFAULT
+ PRIORITY_LOWEST -> YukiHookPriority.LOWEST
+ PRIORITY_HIGHEST -> YukiHookPriority.HIGHEST
+ else -> error("Invalid Hook Priority $this")
+ }
+
/**
* Hook 核心功能实现类
*
@@ -257,7 +270,7 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
internal var finder: MemberBaseFinder? = null
/** 当前被 Hook 的 [Method]、[Constructor] 实例数组 */
- private val memberUnhooks = HashSet()
+ private val hookedMembers = HashSet()
/** 当前需要 Hook 的 [Method]、[Constructor] */
internal val members = HashSet()
@@ -509,7 +522,7 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
/** Hook 执行入口 */
@PublishedApi
internal fun hook() {
- if (YukiHookBridge.hasXposedBridge.not() || isHooked || isDisableMemberRunHook) return
+ if (HookApiCategoryHelper.hasAvailableHookApi.not() || isHooked || isDisableMemberRunHook) return
isHooked = true
finder?.printLogIfExist()
if (hookClass.instance == null) {
@@ -524,11 +537,11 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
runCatching {
member.hook().also {
when {
- it.first?.member == null -> error("Hook Member [$member] failed")
- it.second -> onAlreadyHookedCallback?.invoke(it.first?.member!!)
- else -> it.first?.also { e ->
- memberUnhooks.add(e)
- onHookedCallback?.invoke(e.member!!)
+ it.hookedMember?.member == null -> error("Hook Member [$member] failed")
+ it.isAlreadyHooked -> onAlreadyHookedCallback?.invoke(it.hookedMember.member!!)
+ else -> {
+ hookedMembers.add(it.hookedMember)
+ onHookedCallback?.invoke(it.hookedMember.member!!)
}
}
}
@@ -552,14 +565,14 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
/**
* Hook [Method]、[Constructor]
- * @return [Pair] - ([YukiMemberHook.Unhook] or null,[Boolean] 是否已经 Hook)
+ * @return [YukiHookResult]
*/
- private fun Member.hook(): Pair {
+ private fun Member.hook(): YukiHookResult {
/** 定义替换 Hook 的 [HookParam] */
val replaceHookParam = HookParam(creatorInstance = this@YukiMemberHookCreator)
/** 定义替换 Hook 回调方法体 */
- val replaceMent = object : YukiMemberReplacement(priority) {
+ val replaceMent = object : YukiMemberReplacement(priority.toPriority()) {
override fun replaceHookedMember(param: Param) =
replaceHookParam.assign(param).let { assign ->
runCatching {
@@ -585,7 +598,7 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
val afterHookParam = HookParam(creatorInstance = this@YukiMemberHookCreator)
/** 定义前后 Hook 回调方法体 */
- val beforeAfterHook = object : YukiMemberHook(priority) {
+ val beforeAfterHook = object : YukiMemberHook(priority.toPriority()) {
override fun beforeHookedMember(param: Param) {
beforeHookParam.assign(param).also { assign ->
runCatching {
@@ -803,7 +816,7 @@ class YukiMemberHookCreator @PublishedApi internal constructor(
* @param result 回调是否成功
*/
fun remove(result: (Boolean) -> Unit = {}) {
- memberUnhooks.takeIf { it.isNotEmpty() }?.apply {
+ hookedMembers.takeIf { it.isNotEmpty() }?.apply {
forEach {
it.remove()
onHookLogMsg(msg = "Remove Hooked Member [${it.member}] done [$tag]")
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.kt
index 1c8409e9..db775f16 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.kt
@@ -32,13 +32,13 @@ package com.highcapable.yukihookapi.hook.core
import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.bean.HookResources
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.param.PackageParam
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
/**
* [YukiHookAPI] 的 [Resources] 核心 Hook 实现类
@@ -67,7 +67,7 @@ class YukiResourcesHookCreator @PublishedApi internal constructor(
/** Hook 执行入口 */
@PublishedApi
internal fun hook() {
- if (YukiHookBridge.hasXposedBridge.not()) return
+ if (HookApiCategoryHelper.hasAvailableHookApi.not()) return
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
if (preHookResources.isEmpty()) return yLoggerW(msg = "Hook Resources is empty, hook aborted")
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategory.kt
new file mode 100644
index 00000000..1a440b34
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategory.kt
@@ -0,0 +1,39 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.compat
+
+/**
+ * Hook API 类型定义类
+ */
+internal enum class HookApiCategory {
+ /** 原版 Xposed API */
+ ROVO89_XPOSED,
+
+ /** 未知类型的 API */
+ UNKNOWN
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategoryHelper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategoryHelper.kt
new file mode 100644
index 00000000..a6101405
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiCategoryHelper.kt
@@ -0,0 +1,64 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.compat
+
+import de.robv.android.xposed.XposedBridge
+
+/**
+ * Hook API 类型工具类
+ */
+internal object HookApiCategoryHelper {
+
+ /** 目前支持的 API 类型定义 - 按优先级正序排列 */
+ private val supportedCategories = arrayOf(HookApiCategory.ROVO89_XPOSED)
+
+ /**
+ * 获取当前支持的 API 类型
+ * @return [HookApiCategory]
+ */
+ internal val currentCategory
+ get() = supportedCategories.let { categories ->
+ categories.forEach { if (hasCategory(it)) return@let it }
+ HookApiCategory.UNKNOWN
+ }
+
+ /**
+ * 获取当前环境是否存在可用的 Hook API
+ * @return [Boolean]
+ */
+ internal val hasAvailableHookApi get() = currentCategory != HookApiCategory.UNKNOWN
+
+ /**
+ * 判断当前运行环境是否存在当前 Hook API 类型
+ * @return [Boolean]
+ */
+ private fun hasCategory(category: HookApiCategory) = when (category) {
+ HookApiCategory.ROVO89_XPOSED -> runCatching { XposedBridge.getXposedVersion(); true }.getOrNull() ?: false
+ else -> false
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiProperty.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiProperty.kt
new file mode 100644
index 00000000..0a72f39d
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookApiProperty.kt
@@ -0,0 +1,101 @@
+/*
+ * 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 2023/1/9.
+ */
+@file:Suppress("MemberVisibilityCanBePrivate")
+
+package com.highcapable.yukihookapi.hook.core.api.compat
+
+import com.highcapable.yukihookapi.hook.factory.classOf
+import com.highcapable.yukihookapi.hook.factory.field
+import com.highcapable.yukihookapi.hook.factory.hasClass
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
+import de.robv.android.xposed.XposedBridge
+
+/**
+ * Hook API 相关属性
+ */
+internal object HookApiProperty {
+
+ /** TaiChi (太极) Xposed 框架名称 */
+ internal const val TAICHI_XPOSED_NAME = "TaiChi"
+
+ /** BugXposed (应用转生) Xposed 框架名称 */
+ internal const val BUG_XPOSED_NAME = "BugXposed"
+
+ /** TaiChi (太极) ExposedBridge 完整类名 */
+ internal const val EXPOSED_BRIDGE_CLASS_NAME = "me.weishu.exposed.ExposedBridge"
+
+ /** BugXposed (应用转生) BugLoad 完整类名 */
+ internal const val BUG_LOAD_CLASS_NAME = "com.bug.load.BugLoad"
+
+ /**
+ * 获取当前 Hook 框架的名称
+ * @return [String] 无法获取会返回 unknown - 获取失败会返回 invalid
+ */
+ internal val name
+ get() = when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> when {
+ EXPOSED_BRIDGE_CLASS_NAME.hasClass(AppParasitics.currentApplication?.classLoader) -> TAICHI_XPOSED_NAME
+ BUG_LOAD_CLASS_NAME.hasClass(AppParasitics.currentApplication?.classLoader) -> BUG_XPOSED_NAME
+ else -> runCatching {
+ classOf().field { name = "TAG" }.ignored().get().string().takeIf { it.isNotBlank() }
+ ?.replace("Bridge", "")?.replace("-", "")?.trim() ?: "unknown"
+ }.getOrNull() ?: "invalid"
+ }
+ HookApiCategory.UNKNOWN -> "unknown"
+ }
+
+ /**
+ * 获取当前 Hook 框架的 API 版本
+ * @return [Int] 无法获取会返回 -1
+ */
+ internal val apiLevel
+ get() = when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> runCatching { XposedBridge.getXposedVersion() }.getOrNull() ?: -1
+ HookApiCategory.UNKNOWN -> -1
+ }
+
+ /**
+ * 获取当前 Hook 框架的版本名称
+ * @return [String] 无法获取会返回 unknown - 不支持会返回 unsupported
+ */
+ internal val versionName
+ get() = when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> "unsupported"
+ HookApiCategory.UNKNOWN -> "unknown"
+ }
+
+ /**
+ * 获取当前 Hook 框架的版本号
+ * @return [Int] 无法获取会返回 -1 - 不支持会返回 0
+ */
+ internal val versionCode
+ get() = when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> 0
+ HookApiCategory.UNKNOWN -> -1
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookCompatHelper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookCompatHelper.kt
new file mode 100644
index 00000000..0b325c28
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/compat/HookCompatHelper.kt
@@ -0,0 +1,143 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.compat
+
+import com.highcapable.yukihookapi.hook.core.api.factory.YukiHookCallbackDelegate
+import com.highcapable.yukihookapi.hook.core.api.factory.callAfterHookedMember
+import com.highcapable.yukihookapi.hook.core.api.factory.callBeforeHookedMember
+import com.highcapable.yukihookapi.hook.core.api.priority.YukiHookPriority
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+import de.robv.android.xposed.XC_MethodHook
+import de.robv.android.xposed.XposedBridge
+import java.lang.reflect.Member
+
+/**
+ * Hook API 兼容层处理工具类
+ */
+internal object HookCompatHelper {
+
+ /**
+ * [HookApiCategory.ROVO89_XPOSED]
+ *
+ * 兼容对接已 Hook 的 [Member] 接口
+ * @return [YukiMemberHook.HookedMember]
+ */
+ private fun XC_MethodHook.Unhook.compat() = YukiHookCallbackDelegate.createHookedMemberCallback(hookedMethod) { unhook() }
+
+ /**
+ * [HookApiCategory.ROVO89_XPOSED]
+ *
+ * 兼容对接 Hook 结果回调接口
+ * @return [YukiHookCallback.Param]
+ */
+ private fun XC_MethodHook.MethodHookParam.compat() =
+ YukiHookCallbackDelegate.createParamCallback(
+ dataExtra = extra,
+ member = method,
+ instance = thisObject,
+ args = args,
+ hasThrowable = hasThrowable(),
+ resultCallback = { result = it },
+ throwableCallback = { throwable = it },
+ result = result,
+ throwable = throwable
+ )
+
+ /**
+ * 兼容对接 Hook 回调接口
+ * @return [Any] 原始接口
+ */
+ private fun YukiHookCallback.compat() = when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> object : XC_MethodHook(
+ when (priority) {
+ YukiHookPriority.DEFAULT -> 50
+ YukiHookPriority.LOWEST -> -10000
+ YukiHookPriority.HIGHEST -> 10000
+ }
+ ) {
+ override fun beforeHookedMethod(param: MethodHookParam?) {
+ if (param == null) return
+ this@compat.callBeforeHookedMember(param.compat())
+ }
+
+ override fun afterHookedMethod(param: MethodHookParam?) {
+ if (param == null) return
+ this@compat.callAfterHookedMember(param.compat())
+ }
+ }
+ HookApiCategory.UNKNOWN -> throwUnsupportedHookApiError()
+ }
+
+ /**
+ * Hook [Member]
+ * @param member 需要 Hook 的方法、构造方法
+ * @param callback 回调
+ * @return [YukiMemberHook.HookedMember] or null
+ */
+ internal fun hookMember(member: Member?, callback: YukiHookCallback): YukiMemberHook.HookedMember? {
+ if (member == null) return null
+ return when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> XposedBridge.hookMethod(member, callback.compat()).compat()
+ HookApiCategory.UNKNOWN -> throwUnsupportedHookApiError()
+ }
+ }
+
+ /**
+ * 执行未进行 Hook 的原始 [Member]
+ * @param member 实例
+ * @param args 参数实例
+ * @return [Any] or null
+ */
+ internal fun invokeOriginalMember(member: Member?, instance: Any?, vararg args: Any?): Any? {
+ if (member == null) return null
+ return when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> XposedBridge.invokeOriginalMethod(member, instance, args)
+ HookApiCategory.UNKNOWN -> throwUnsupportedHookApiError()
+ }
+ }
+
+ /**
+ * 使用当前 Hook API 自带的日志功能打印日志
+ * @param msg 日志打印的内容
+ * @param e 异常堆栈信息 - 默认空
+ */
+ internal fun logByHooker(msg: String, e: Throwable? = null) {
+ when (HookApiCategoryHelper.currentCategory) {
+ HookApiCategory.ROVO89_XPOSED -> {
+ XposedBridge.log(msg)
+ e?.also { XposedBridge.log(it) }
+ }
+ HookApiCategory.UNKNOWN -> throwUnsupportedHookApiError()
+ }
+ }
+
+ /** 抛出不支持的 API 类型异常 */
+ private fun throwUnsupportedHookApiError(): Nothing =
+ error("YukiHookAPI cannot support current Hook API or cannot found any available Hook APIs in current environment")
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/factory/YukiHookDelegateFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/factory/YukiHookDelegateFactory.kt
new file mode 100644
index 00000000..eabe1e1d
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/factory/YukiHookDelegateFactory.kt
@@ -0,0 +1,117 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.factory
+
+import android.os.Bundle
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberReplacement
+import com.highcapable.yukihookapi.hook.core.api.store.YukiHookCacheStore
+import java.lang.reflect.Member
+
+/**
+ * Hook API 回调事件代理类
+ */
+internal object YukiHookCallbackDelegate {
+
+ /**
+ * 创建 [YukiMemberHook.HookedMember] 实例
+ * @param member 当前 [Member]
+ * @param removeCallback 回调解除 Hook 事件
+ * @return [YukiMemberHook.HookedMember]
+ */
+ internal fun createHookedMemberCallback(member: Member, removeCallback: () -> Unit) =
+ object : YukiMemberHook.HookedMember() {
+ override val member get() = member
+ override fun remove() {
+ removeCallback()
+ runCatching { YukiHookCacheStore.hookedMembers.remove(this) }
+ }
+ }
+
+ /**
+ * 创建 [YukiHookCallback.Param] 实例
+ * @param dataExtra 当前回调范围内的数据存储实例
+ * @param member [Member] 实例
+ * @param instance 当前实例对象
+ * @param args 方法、构造方法数组
+ * @param hasThrowable 是否存在设置过的方法调用抛出异常
+ * @param resultCallback 回调设置当前 Hook 方法的返回值 (结果)
+ * @param throwableCallback 回调设置当前 Hook 方法调用抛出的异常
+ * @param result 当前 Hook 方法返回值 (结果)
+ * @param throwable 当前 Hook 方法调用抛出的异常
+ * @return [YukiHookCallback.Param]
+ */
+ internal fun createParamCallback(
+ dataExtra: Bundle,
+ member: Member?,
+ instance: Any?,
+ args: Array?,
+ hasThrowable: Boolean,
+ resultCallback: (Any?) -> Unit,
+ throwableCallback: (Throwable?) -> Unit,
+ result: Any?,
+ throwable: Throwable?
+ ) = object : YukiHookCallback.Param {
+ override val dataExtra get() = dataExtra
+ override val member get() = member
+ override val instance get() = instance
+ override val args get() = args
+ override val hasThrowable get() = hasThrowable
+ override var result
+ get() = result
+ set(value) {
+ resultCallback(value)
+ }
+ override var throwable
+ get() = throwable
+ set(value) {
+ throwableCallback(value)
+ }
+ }
+}
+
+/**
+ * 调用 [YukiMemberHook.beforeHookedMember] 事件
+ * @param param Hook 结果回调接口
+ */
+internal fun YukiHookCallback.callBeforeHookedMember(param: YukiHookCallback.Param) {
+ if (this !is YukiMemberHook) error("Invalid YukiHookCallback type")
+ if (this is YukiMemberReplacement)
+ param.result = replaceHookedMember(param)
+ else beforeHookedMember(param)
+}
+
+/**
+ * 调用 [YukiMemberHook.afterHookedMember] 事件
+ * @param param Hook 结果回调接口
+ */
+internal fun YukiHookCallback.callAfterHookedMember(param: YukiHookCallback.Param) {
+ if (this !is YukiMemberHook) error("Invalid YukiHookCallback type")
+ afterHookedMember(param)
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/helper/YukiHookHelper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/helper/YukiHookHelper.kt
new file mode 100644
index 00000000..4eb574a6
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/helper/YukiHookHelper.kt
@@ -0,0 +1,104 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.helper
+
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
+import com.highcapable.yukihookapi.hook.core.api.compat.HookCompatHelper
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
+import com.highcapable.yukihookapi.hook.core.api.result.YukiHookResult
+import com.highcapable.yukihookapi.hook.core.api.store.YukiHookCacheStore
+import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
+import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder
+import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
+import com.highcapable.yukihookapi.hook.log.yLoggerE
+import java.lang.reflect.Member
+
+/**
+ * Hook 核心功能实现工具类
+ */
+internal object YukiHookHelper {
+
+ /**
+ * Hook [BaseFinder.BaseResult]
+ * @param traction 直接调用 [BaseFinder.BaseResult]
+ * @param callback 回调
+ * @return [YukiHookResult]
+ */
+ internal fun hook(traction: BaseFinder.BaseResult, callback: YukiHookCallback) = runCatching {
+ val member: Member? = when (traction) {
+ is MethodFinder.Result -> traction.ignored().give()
+ is ConstructorFinder.Result -> traction.ignored().give()
+ else -> error("Unexpected BaseFinder result interface type")
+ }
+ hookMember(member, callback)
+ }.onFailure { yLoggerE(msg = "An exception occurred when hooking internal function", e = it) }.getOrNull() ?: YukiHookResult()
+
+ /**
+ * Hook [Member]
+ * @param member 需要 Hook 的方法、构造方法
+ * @param callback 回调
+ * @return [YukiHookResult]
+ */
+ internal fun hookMember(member: Member?, callback: YukiHookCallback): YukiHookResult {
+ runCatching {
+ YukiHookCacheStore.hookedMembers.takeIf { it.isNotEmpty() }?.forEach {
+ if (it.member.toString() == member?.toString()) return YukiHookResult(isAlreadyHooked = true, it)
+ }
+ }
+ return HookCompatHelper.hookMember(member, callback).let {
+ if (it != null) YukiHookCacheStore.hookedMembers.add(it)
+ YukiHookResult(hookedMember = it)
+ }
+ }
+
+ /**
+ * 执行原始 [Member]
+ *
+ * 未进行 Hook 的 [Member]
+ * @param member 实例
+ * @param args 参数实例
+ * @return [Any] or null
+ */
+ internal fun invokeOriginalMember(member: Member?, instance: Any?, vararg args: Any?) =
+ if (HookApiCategoryHelper.hasAvailableHookApi && YukiHookCacheStore.hookedMembers.any { it.member.toString() == member.toString() })
+ member?.let {
+ runCatching { HookCompatHelper.invokeOriginalMember(member, instance, args) }
+ .onFailure { yLoggerE(msg = "Invoke original Member [$member] failed", e = it) }
+ .getOrNull()
+ }
+ else null
+
+ /**
+ * 使用当前 Hook API 自带的日志功能打印日志
+ * @param msg 日志打印的内容
+ * @param e 异常堆栈信息 - 默认空
+ */
+ internal fun logByHooker(msg: String, e: Throwable? = null) {
+ if (HookApiCategoryHelper.hasAvailableHookApi) HookCompatHelper.logByHooker(msg, e)
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.kt
new file mode 100644
index 00000000..e9ee95e2
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.kt
@@ -0,0 +1,43 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.priority
+
+/**
+ * Hook 回调优先级配置类
+ */
+internal enum class YukiHookPriority {
+
+ /** 默认 Hook 回调优先级 */
+ DEFAULT,
+
+ /** 延迟回调 Hook 方法结果 */
+ LOWEST,
+
+ /** 更快回调 Hook 方法结果 */
+ HIGHEST
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiHookCallback.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiHookCallback.kt
new file mode 100644
index 00000000..2a4a011a
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiHookCallback.kt
@@ -0,0 +1,89 @@
+/*
+ * 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/4/9.
+ * This file is Modified by fankes on 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.proxy
+
+import android.os.Bundle
+import com.highcapable.yukihookapi.hook.core.api.priority.YukiHookPriority
+import java.lang.reflect.Member
+
+/**
+ * Hook 回调接口抽象类
+ * @param priority Hook 优先级
+ */
+internal abstract class YukiHookCallback(internal open val priority: YukiHookPriority) {
+
+ /**
+ * Hook 结果回调接口
+ */
+ internal interface Param {
+
+ /**
+ * 当前回调范围内的数据存储实例
+ * @return [Bundle]
+ */
+ val dataExtra: Bundle
+
+ /**
+ * [Member] 实例
+ * @return [Member] or null
+ */
+ val member: Member?
+
+ /**
+ * 当前实例对象
+ * @return [Any] or null
+ */
+ val instance: Any?
+
+ /**
+ * 方法、构造方法数组
+ * @return [Array] or null
+ */
+ val args: Array?
+
+ /**
+ * 获取、设置方法返回值 (结果)
+ * @return [Any] or null
+ */
+ var result: Any?
+
+ /**
+ * 是否存在设置过的方法调用抛出异常
+ * @return [Boolean]
+ */
+ val hasThrowable: Boolean
+
+ /**
+ * 获取、设置方法调用抛出的异常
+ * @return [Throwable] or null
+ * @throws Throwable
+ */
+ var throwable: Throwable?
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberHook.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberHook.kt
new file mode 100644
index 00000000..34274b69
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberHook.kt
@@ -0,0 +1,66 @@
+/*
+ * 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/4/9.
+ * This file is Modified by fankes on 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.proxy
+
+import com.highcapable.yukihookapi.hook.core.api.priority.YukiHookPriority
+import java.lang.reflect.Member
+
+/**
+ * Hook 方法回调接口抽象类
+ * @param priority Hook 优先级 - 默认 [YukiHookPriority.DEFAULT]
+ */
+internal abstract class YukiMemberHook(override val priority: YukiHookPriority = YukiHookPriority.DEFAULT) : YukiHookCallback(priority) {
+
+ /**
+ * 在方法执行之前注入
+ * @param param Hook 结果回调接口
+ */
+ internal open fun beforeHookedMember(param: Param) {}
+
+ /**
+ * 在方法执行之后注入
+ * @param param Hook 结果回调接口
+ */
+ internal open fun afterHookedMember(param: Param) {}
+
+ /**
+ * 已经 Hook 且可被解除 Hook 的 [Member] 实现接口抽象类
+ */
+ internal abstract class HookedMember internal constructor() {
+
+ /**
+ * 当前被 Hook 的 [Member]
+ * @return [Member] or null
+ */
+ internal abstract val member: Member?
+
+ /** 解除 Hook */
+ internal abstract fun remove()
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/helper/YukiHookAppHelper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberReplacement.kt
similarity index 55%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/helper/YukiHookAppHelper.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberReplacement.kt
index 50c3da14..9acbc07d 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/helper/YukiHookAppHelper.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/proxy/YukiMemberReplacement.kt
@@ -24,41 +24,28 @@
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/9.
+ * This file is Modified by fankes on 2023/1/9.
*/
-package com.highcapable.yukihookapi.hook.xposed.helper
+package com.highcapable.yukihookapi.hook.core.api.proxy
-import android.app.AndroidAppHelper
-import android.app.Application
-import android.content.pm.ApplicationInfo
+import com.highcapable.yukihookapi.hook.core.api.priority.YukiHookPriority
/**
- * 这是一个宿主 Hook 功能接口
- *
- * 对接 [AndroidAppHelper]
+ * Hook 替换方法回调接口抽象类
+ * @param priority Hook 优先级- 默认 [YukiHookPriority.DEFAULT]
*/
-internal object YukiHookAppHelper {
+internal abstract class YukiMemberReplacement(override val priority: YukiHookPriority = YukiHookPriority.DEFAULT) : YukiMemberHook(priority) {
+
+ override fun beforeHookedMember(param: Param) {
+ param.result = replaceHookedMember(param)
+ }
+
+ override fun afterHookedMember(param: Param) {}
/**
- * 获取当前宿主的 [Application]
- * @return [Application] or null
+ * 拦截替换为指定结果
+ * @param param Hook 结果回调接口
+ * @return [Any] or null
*/
- internal fun currentApplication() = runCatching { AndroidAppHelper.currentApplication() }.getOrNull()
-
- /**
- * 获取当前宿主的 [ApplicationInfo]
- * @return [ApplicationInfo] or null
- */
- internal fun currentApplicationInfo() = runCatching { AndroidAppHelper.currentApplicationInfo() }.getOrNull()
-
- /**
- * 获取当前宿主的包名
- * @return [String] or null
- */
- internal fun currentPackageName() = runCatching { AndroidAppHelper.currentPackageName() }.getOrNull()
-
- /**
- * 获取当前宿主的进程名
- * @return [String] or null
- */
- internal fun currentProcessName() = runCatching { AndroidAppHelper.currentProcessName() }.getOrNull()
+ abstract fun replaceHookedMember(param: Param): Any?
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/result/YukiHookResult.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/result/YukiHookResult.kt
new file mode 100644
index 00000000..81d0f1bc
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/result/YukiHookResult.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.result
+
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+
+/**
+ * Hook 结果实现类
+ * @param isAlreadyHooked 是否已经被 Hook - 默认否
+ * @param hookedMember 当前 Hook 的实例对象 - 默认空
+ */
+internal data class YukiHookResult(val isAlreadyHooked: Boolean = false, val hookedMember: YukiMemberHook.HookedMember? = null)
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/store/YukiHookCacheStore.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/store/YukiHookCacheStore.kt
new file mode 100644
index 00000000..ee911b99
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/api/store/YukiHookCacheStore.kt
@@ -0,0 +1,41 @@
+/*
+ * 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/7/28.
+ * This file is Modified by fankes on 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.core.api.store
+
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+import java.lang.reflect.Member
+
+/**
+ * Hook 过程的功能缓存实现类
+ */
+internal object YukiHookCacheStore {
+
+ /** 已经 Hook 的 [Member] 数组 */
+ internal val hookedMembers = HashSet()
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/ClassBaseFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/ClassBaseFinder.kt
index ad8c2541..4e57fbc6 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/ClassBaseFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/ClassBaseFinder.kt
@@ -29,9 +29,9 @@ package com.highcapable.yukihookapi.hook.core.finder.base
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
/**
* 这是 [Class] 查找类功能的基本类实现
@@ -60,11 +60,11 @@ abstract class ClassBaseFinder internal constructor(internal open val loaderSet:
internal fun compatType(any: Any?, tag: String) = any?.compat(tag, loaderSet)
/**
- * 在开启 [YukiHookAPI.Configs.isDebug] 且在 [YukiHookBridge.hasXposedBridge] 情况下输出调试信息
+ * 在开启 [YukiHookAPI.Configs.isDebug] 且在 [HookApiCategoryHelper.hasAvailableHookApi] 情况下输出调试信息
* @param msg 调试日志内容
*/
internal fun onDebuggingMsg(msg: String) {
- if (YukiHookAPI.Configs.isDebug && YukiHookBridge.hasXposedBridge) yLoggerI(msg = msg)
+ if (YukiHookAPI.Configs.isDebug && HookApiCategoryHelper.hasAvailableHookApi) yLoggerI(msg = msg)
}
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/MemberBaseFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/MemberBaseFinder.kt
index 08e4b544..447864fc 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/MemberBaseFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/MemberBaseFinder.kt
@@ -30,11 +30,11 @@ package com.highcapable.yukihookapi.hook.core.finder.base
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.utils.await
import com.highcapable.yukihookapi.hook.utils.unit
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Member
@@ -145,11 +145,11 @@ abstract class MemberBaseFinder internal constructor(
}
/**
- * 在开启 [YukiHookAPI.Configs.isDebug] 且在 [YukiHookBridge.hasXposedBridge] 且在 Hook 过程中情况下输出调试信息
+ * 在开启 [YukiHookAPI.Configs.isDebug] 且在 [HookApiCategoryHelper.hasAvailableHookApi] 且在 Hook 过程中情况下输出调试信息
* @param msg 调试日志内容
*/
internal fun onDebuggingMsg(msg: String) {
- if (YukiHookAPI.Configs.isDebug && YukiHookBridge.hasXposedBridge && hookInstance != null) yLoggerI(msg = msg)
+ if (YukiHookAPI.Configs.isDebug && HookApiCategoryHelper.hasAvailableHookApi && hookInstance != null) yLoggerI(msg = msg)
}
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.kt
index fda6fbed..47ff5f35 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.kt
@@ -53,7 +53,7 @@ import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.utils.await
import com.highcapable.yukihookapi.hook.utils.runBlocking
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import dalvik.system.BaseDexClassLoader
import java.lang.reflect.Constructor
import java.lang.reflect.Field
@@ -81,6 +81,12 @@ class DexClassFinder @PublishedApi internal constructor(
/** 缓存的存储文件名 */
private const val CACHE_FILE_NAME = "config_yukihook_cache_obfuscate_classes"
+ /**
+ * 获取当前运行环境的 [Context]
+ * @return [Context] or null
+ */
+ private val currentContext get() = AppParasitics.hostApplication ?: AppParasitics.currentApplication
+
/**
* 通过 [Context] 获取当前 [SharedPreferences]
* @param versionName 版本名称 - 默认空
@@ -97,11 +103,11 @@ class DexClassFinder @PublishedApi internal constructor(
* 清除当前 [DexClassFinder] 的 [Class] 缓存
*
* 适用于全部通过 [ClassLoader.searchClass] or [PackageParam.searchClass] 获取的 [DexClassFinder]
- * @param context 当前 [Context] - 不填默认获取 [YukiHookAppHelper.currentApplication]
+ * @param context 当前 [Context] - 不填默认获取 [currentContext]
* @param versionName 版本名称 - 默认空
* @param versionCode 版本号 - 默认空
*/
- fun clearCache(context: Context? = YukiHookAppHelper.currentApplication(), versionName: String? = null, versionCode: Long? = null) {
+ fun clearCache(context: Context? = currentContext, versionName: String? = null, versionCode: Long? = null) {
context?.currentSp(versionName, versionCode)?.edit()?.clear()?.apply()
?: yLoggerW(msg = "Cannot clear cache for DexClassFinder because got null context instance")
}
@@ -440,7 +446,7 @@ class DexClassFinder @PublishedApi internal constructor(
* @return [HashSet]<[Class]>
*/
private fun readFromCache(): HashSet> =
- if (async && name.isNotBlank()) YukiHookAppHelper.currentApplication()?.let {
+ if (async && name.isNotBlank()) currentContext?.let {
hashSetOf>().also { classes ->
it.currentSp().getStringSet(name, emptySet())?.takeIf { it.isNotEmpty() }
?.forEach { className -> if (className.hasClass(loaderSet)) classes.add(className.toClass(loaderSet)) }
@@ -454,7 +460,7 @@ class DexClassFinder @PublishedApi internal constructor(
private fun HashSet>.saveToCache() {
if (name.isNotBlank() && isNotEmpty()) hashSetOf().also { names ->
takeIf { it.isNotEmpty() }?.forEach { names.add(it.name) }
- YukiHookAppHelper.currentApplication()?.also {
+ currentContext?.also {
if (it.packageName == "android") error("Cannot create classes cache for \"android\", please remove \"name\" param")
it.currentSp().edit().apply { putStringSet(name, names) }.apply()
}
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.kt
index 0f013a63..91c89b7b 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.kt
@@ -289,7 +289,6 @@ class ConstructorFinder @PublishedApi internal constructor(
@YukiPrivateApi
override fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
-
@YukiPrivateApi
override fun denied(throwable: Throwable?) = Process(isNoSuch = true, throwable)
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.kt
index 2b2bfabc..0c706a91 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.kt
@@ -32,6 +32,7 @@ package com.highcapable.yukihookapi.hook.core.finder.members
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator
+import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.core.finder.base.MemberBaseFinder
import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData
@@ -44,7 +45,6 @@ import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
import com.highcapable.yukihookapi.hook.type.defined.VagueType
import com.highcapable.yukihookapi.hook.utils.runBlocking
import com.highcapable.yukihookapi.hook.utils.unit
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
import java.lang.reflect.Member
import java.lang.reflect.Method
@@ -377,7 +377,6 @@ class MethodFinder @PublishedApi internal constructor(
@YukiPrivateApi
override fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
-
@YukiPrivateApi
override fun denied(throwable: Throwable?) = Process(isNoSuch = true, throwable)
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt
index 718e15fe..228e6e6c 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt
@@ -46,8 +46,6 @@ import com.highcapable.yukihookapi.hook.type.java.NoSuchFieldErrorClass
import com.highcapable.yukihookapi.hook.type.java.NoSuchMethodErrorClass
import com.highcapable.yukihookapi.hook.utils.*
import com.highcapable.yukihookapi.hook.utils.value
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import dalvik.system.BaseDexClassLoader
import java.lang.reflect.Constructor
@@ -119,12 +117,7 @@ internal object ReflectionTool {
*/
fun loadWithDefaultClassLoader() = if (initialize.not()) loader?.loadClass(name) else classForName(name, initialize, loader)
return ReflectsCacheStore.findClass(hashCode) ?: runCatching {
- when {
- YukiHookBridge.hasXposedBridge -> runCatching { if (initialize.not()) YukiHookHelper.findClass(name, loader) else null }
- .getOrNull() ?: loadWithDefaultClassLoader() ?: classForName(name, initialize)
- loader == null -> classForName(name, initialize)
- else -> loadWithDefaultClassLoader()
- }.also { ReflectsCacheStore.putClass(hashCode, it) }
+ (loadWithDefaultClassLoader() ?: classForName(name, initialize)).also { ReflectsCacheStore.putClass(hashCode, it) }
}.getOrNull() ?: throw createException(loader ?: AppParasitics.baseClassLoader, name = "Class", "name:[$name]")
}
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.kt
index 4220b024..fd7ffd4a 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.kt
@@ -30,28 +30,11 @@ package com.highcapable.yukihookapi.hook.entity
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.param.PackageParam
-import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
/**
* [YukiHookAPI] 的子类 Hooker 实现
*
- * 也许你的 Module 中存在多个 Hooker - 继承此类可以方便帮你管理每个 Hooker
- *
- * 你可以继续继承此类进行自定义 Hooker 相关参数
- *
- * 你可以在 [IYukiHookXposedInit] 的 [IYukiHookXposedInit.onHook] 中实现如下用法:
- *
- * 1.调用 [YukiHookAPI.encase]
- *
- * ```kotlin
- * encase(MainHooker(), SecondHooker(), ThirdHooker() ...)
- * ```
- *
- * 2.调用 [PackageParam.loadHooker]
- *
- * ```kotlin
- * loadHooker(hooker = CustomHooker())
- * ```
+ * 也许你的模块中存在多个功能模块 (Hooker) - 继承并使用此类可以方便帮你管理每个功能模块 (Hooker)
*
* 更多请参考 [InjectYukiHookWithXposed] 中的注解内容
*
@@ -66,7 +49,7 @@ abstract class YukiBaseHooker : PackageParam() {
* @param packageParam 需要使用的 [PackageParam]
*/
internal fun assignInstance(packageParam: PackageParam) {
- baseAssignInstance(packageParam)
+ assign(packageParam.wrapper)
onHook()
}
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 d901c9ea..f41d5e98 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
@@ -40,7 +40,7 @@ import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
import com.highcapable.yukihookapi.hook.core.finder.type.factory.*
import com.highcapable.yukihookapi.hook.type.java.*
-import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleStatus
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import dalvik.system.BaseDexClassLoader
import java.lang.reflect.*
@@ -421,7 +421,7 @@ inline fun Class<*>.allFields(isAccessible: Boolean = true, result: (index: Int,
*/
@PublishedApi
internal fun Class<*>.checkingInternal() {
- if (name == YukiHookModuleStatus.IMPL_CLASS_NAME) return
+ if (name == YukiXposedModuleStatus.IMPL_CLASS_NAME) return
if (name == classOf().name || name.startsWith("com.highcapable.yukihookapi.hook")) throw RuntimeException(
"!!!DO NOT ALLOWED!!! You cannot hook or reflection to call the internal class of the YukiHookAPI itself, " +
"The called class is [$this]"
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/log/LoggerFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/log/LoggerFactory.kt
index 7528ab69..c6d2e36d 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/log/LoggerFactory.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/log/LoggerFactory.kt
@@ -32,11 +32,11 @@ package com.highcapable.yukihookapi.hook.log
import android.system.ErrnoException
import android.util.Log
import com.highcapable.yukihookapi.YukiHookAPI
+import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.utils.toStackTrace
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
-import de.robv.android.xposed.XposedBridge
import java.io.File
import java.io.Serializable
import java.text.SimpleDateFormat
@@ -52,16 +52,26 @@ enum class LoggerType {
LOGD,
/**
- * 仅使用 [XposedBridge.log]
+ * 仅在 (Xposed) 宿主环境使用
+ *
+ * - ❗此方法已弃用 - 在之后的版本中将直接被删除
+ *
+ * - ❗请现在转移到 [XPOSED_ENVIRONMENT]
+ */
+ @Deprecated(message = "请使用新的命名方法", ReplaceWith("XPOSED_ENVIRONMENT"))
+ XPOSEDBRIDGE,
+
+ /**
+ * 仅在 (Xposed) 宿主环境使用
*
* - ❗只能在 (Xposed) 宿主环境中使用 - 模块环境将不生效
*/
- XPOSEDBRIDGE,
+ XPOSED_ENVIRONMENT,
/**
* 分区使用
*
- * (Xposed) 宿主环境仅使用 [XPOSEDBRIDGE]
+ * (Xposed) 宿主环境仅使用 [XPOSED_ENVIRONMENT]
*
* 模块环境仅使用 [LOGD]
*/
@@ -70,7 +80,7 @@ enum class LoggerType {
/**
* 同时使用
*
- * (Xposed) 宿主环境使用 [LOGD] 与 [XPOSEDBRIDGE]
+ * (Xposed) 宿主环境使用 [LOGD] 与 [XPOSED_ENVIRONMENT]
*
* 模块环境仅使用 [LOGD]
*/
@@ -105,8 +115,8 @@ data class YukiLoggerData internal constructor(
init {
timestamp = System.currentTimeMillis()
time = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ROOT).format(Date(timestamp))
- packageName = YukiHookBridge.hostProcessName.takeIf { it != "unknown" } ?: YukiHookBridge.modulePackageName
- userId = AppParasitics.findUserId(packageName)
+ packageName = if (YukiXposedModule.isXposedEnvironment) YukiXposedModule.hostProcessName else AppParasitics.currentPackageName
+ userId = AppParasitics.findUserId(AppParasitics.currentPackageName)
}
/**
@@ -285,7 +295,7 @@ object YukiHookLogger {
/**
* 自定义调试日志对外显示的元素
*
- * 只对日志记录和 [XposedBridge.log] 生效
+ * 只对日志记录和 (Xposed) 宿主环境的日志生效
*
* 日志元素的排列将按照你在 [item] 中设置的顺序进行显示
*
@@ -311,14 +321,14 @@ object YukiHookLogger {
}
/**
- * 向控制台和 [XposedBridge] 打印日志 - 最终实现方法
+ * 向控制台和 (Xposed) 宿主环境打印日志 - 最终实现方法
* @param type 日志打印的类型
* @param data 日志数据
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
*/
private fun baseLogger(type: LoggerType, data: YukiLoggerData, isImplicit: Boolean = false) {
/** 打印到 [Log] */
- fun loggerInLogd() = when (data.priority) {
+ fun logByLogd() = when (data.priority) {
"D" -> Log.d(data.tag, data.msg)
"I" -> Log.i(data.tag, data.msg)
"W" -> Log.w(data.tag, data.msg)
@@ -326,25 +336,23 @@ private fun baseLogger(type: LoggerType, data: YukiLoggerData, isImplicit: Boole
else -> Log.wtf(data.tag, data.msg, data.throwable)
}
- /** 打印到 [XposedBridge.log] */
- fun loggerInXposed() {
- XposedBridge.log(data.also { it.isImplicit = isImplicit }.toString())
- data.throwable?.also { e -> XposedBridge.log(e) }
- }
+ /** 打印到 (Xposed) 宿主环境 */
+ fun logByHooker() = YukiHookHelper.logByHooker(data.also { it.isImplicit = isImplicit }.toString(), data.throwable)
+ @Suppress("DEPRECATION")
when (type) {
- LoggerType.LOGD -> loggerInLogd()
- LoggerType.XPOSEDBRIDGE -> loggerInXposed()
- LoggerType.SCOPE -> if (YukiHookBridge.hasXposedBridge) loggerInXposed() else loggerInLogd()
+ LoggerType.LOGD -> logByLogd()
+ LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> logByHooker()
+ LoggerType.SCOPE -> if (YukiXposedModule.isXposedEnvironment) logByHooker() else logByLogd()
LoggerType.BOTH -> {
- loggerInLogd()
- if (YukiHookBridge.hasXposedBridge) loggerInXposed()
+ logByLogd()
+ if (YukiXposedModule.isXposedEnvironment) logByHooker()
}
}
if (isImplicit.not() && YukiHookLogger.Configs.isRecord) YukiHookLogger.inMemoryData.add(data)
}
/**
- * [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - D
+ * [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - D
* @param msg 日志打印的内容
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
@@ -355,7 +363,7 @@ internal fun yLoggerD(msg: String, isImplicit: Boolean = false, isDisableLog: Bo
}
/**
- * [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - I
+ * [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - I
* @param msg 日志打印的内容
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
@@ -366,7 +374,7 @@ internal fun yLoggerI(msg: String, isImplicit: Boolean = false, isDisableLog: Bo
}
/**
- * [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - W
+ * [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - W
* @param msg 日志打印的内容
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
@@ -377,7 +385,7 @@ internal fun yLoggerW(msg: String, isImplicit: Boolean = false, isDisableLog: Bo
}
/**
- * [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - E
+ * [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - E
* @param msg 日志打印的内容
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
@@ -389,9 +397,9 @@ internal fun yLoggerE(msg: String, e: Throwable? = null, isImplicit: Boolean = f
}
/**
- * 向控制台和 [XposedBridge] 打印日志 - D
+ * 向控制台和 (Xposed) 宿主环境打印日志 - D
*
- * [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
+ * (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
* @param msg 日志打印的内容
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
@@ -400,9 +408,9 @@ fun loggerD(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerT
baseLogger(type, YukiLoggerData(priority = "D", tag = tag, msg = msg))
/**
- * 向控制台和 [XposedBridge] 打印日志 - I
+ * 向控制台和 (Xposed) 宿主环境打印日志 - I
*
- * [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
+ * (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
* @param msg 日志打印的内容
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
@@ -411,9 +419,9 @@ fun loggerI(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerT
baseLogger(type, YukiLoggerData(priority = "I", tag = tag, msg = msg))
/**
- * 向控制台和 [XposedBridge] 打印日志 - W
+ * 向控制台和 (Xposed) 宿主环境打印日志 - W
*
- * [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
+ * (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
* @param msg 日志打印的内容
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
@@ -422,9 +430,9 @@ fun loggerW(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerT
baseLogger(type, YukiLoggerData(priority = "W", tag = tag, msg = msg))
/**
- * 向控制台和 [XposedBridge] 打印日志 - E
+ * 向控制台和 (Xposed) 宿主环境打印日志 - E
*
- * [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
+ * (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
* @param msg 日志打印的内容
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
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 e4f9f88b..d41f0818 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
@@ -31,10 +31,10 @@ package com.highcapable.yukihookapi.hook.param
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator.MemberHookCreator
+import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
import com.highcapable.yukihookapi.hook.factory.classOf
import com.highcapable.yukihookapi.hook.log.yLoggerE
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookCallback
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
import java.lang.reflect.Constructor
import java.lang.reflect.Member
import java.lang.reflect.Method
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 5ba6070b..49c9759b 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
@@ -46,14 +46,13 @@ import com.highcapable.yukihookapi.hook.core.finder.classes.DexClassFinder
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ClassConditions
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.utils.value
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiModuleResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
@@ -63,6 +62,18 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
*/
open class PackageParam internal constructor(@PublishedApi internal var wrapper: PackageParamWrapper? = null) {
+ @PublishedApi
+ internal companion object {
+
+ /** 获取当前 Xposed 模块包名 */
+ @PublishedApi
+ internal val modulePackageName get() = YukiXposedModule.modulePackageName
+
+ /** Android 系统框架名称 */
+ @PublishedApi
+ internal const val SYSTEM_FRAMEWORK_NAME = AppParasitics.SYSTEM_FRAMEWORK_NAME
+ }
+
/** 当前设置的 [ClassLoader] */
private var currentClassLoader: ClassLoader? = null
@@ -77,7 +88,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
*/
var appClassLoader
get() = currentClassLoader ?: wrapper?.appClassLoader
- ?: YukiHookAppHelper.currentApplication()?.classLoader
+ ?: AppParasitics.currentApplication?.classLoader
?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
set(value) {
currentClassLoader = value
@@ -87,7 +98,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 获取当前 Hook APP 的 [ApplicationInfo]
* @return [ApplicationInfo]
*/
- val appInfo get() = wrapper?.appInfo ?: YukiHookAppHelper.currentApplicationInfo() ?: ApplicationInfo()
+ val appInfo get() = wrapper?.appInfo ?: AppParasitics.currentApplicationInfo ?: ApplicationInfo()
/**
* 获取当前 Hook APP 的用户 ID
@@ -103,7 +114,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* - ❗首次装载可能是空的 - 请延迟一段时间再获取或通过设置 [onAppLifecycle] 监听来完成
* @return [Application] or null
*/
- val appContext get() = AppParasitics.hostApplication ?: YukiHookAppHelper.currentApplication()
+ val appContext get() = AppParasitics.hostApplication ?: AppParasitics.currentApplication
/**
* 获取当前 Hook APP 的 Resources
@@ -126,13 +137,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 默认的进程名称是 [packageName]
* @return [String]
*/
- val processName get() = wrapper?.processName ?: YukiHookAppHelper.currentProcessName() ?: packageName
+ val processName get() = wrapper?.processName ?: AppParasitics.currentProcessName
/**
* 获取当前 Hook APP 的包名
* @return [String]
*/
- val packageName get() = wrapper?.packageName ?: YukiHookAppHelper.currentPackageName() ?: ""
+ val packageName get() = wrapper?.packageName ?: AppParasitics.currentPackageName
/**
* 获取当前 Hook APP 是否为第一个 [Application]
@@ -154,7 +165,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* - ❗作为 Hook API 装载时无法使用 - 会获取到空字符串
* @return [String]
*/
- val moduleAppFilePath get() = AppParasitics.moduleAppFilePath
+ val moduleAppFilePath get() = YukiXposedModule.moduleAppFilePath
/**
* 获取当前 Xposed 模块自身 [Resources]
@@ -164,8 +175,8 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @throws IllegalStateException 如果当前 Hook Framework 不支持此功能
*/
val moduleAppResources
- get() = (if (YukiHookAPI.Configs.isEnableModuleAppResourcesCache) AppParasitics.moduleAppResources
- else AppParasitics.dynamicModuleAppResources) ?: error("Current Hook Framework not support moduleAppResources")
+ get() = (if (YukiHookAPI.Configs.isEnableModuleAppResourcesCache) YukiXposedModule.moduleAppResources
+ else YukiXposedModule.dynamicModuleAppResources) ?: error("Current Hook Framework not support moduleAppResources")
/**
* 获得当前使用的存取数据对象缓存实例
@@ -197,11 +208,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
else error("YukiHookDataChannel cannot used in zygote")
/**
- * 赋值并克隆另一个 [PackageParam]
- * @param anotherParam 另一个 [PackageParam]
+ * 设置 [PackageParam] 使用的 [PackageParamWrapper]
+ * @param wrapper [PackageParam] 的参数包装类实例
+ * @return [PackageParam]
*/
- internal fun baseAssignInstance(anotherParam: PackageParam) {
- this.wrapper = anotherParam.wrapper
+ internal fun assign(wrapper: PackageParamWrapper?): PackageParam {
+ this.wrapper = wrapper
+ return this
}
/**
@@ -213,7 +226,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
fun resources() = HookResources(wrapper?.appResources)
/** 刷新当前 Xposed 模块自身 [Resources] */
- fun refreshModuleAppResources() = AppParasitics.refreshModuleAppResources()
+ fun refreshModuleAppResources() = YukiXposedModule.refreshModuleAppResources()
/**
* 监听当前 Hook APP 生命周期装载事件
@@ -292,7 +305,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
*/
inline fun loadApp(isExcludeSelf: Boolean = false, initiate: PackageParam.() -> Unit) {
if (wrapper?.type != HookEntryType.ZYGOTE &&
- (isExcludeSelf.not() || isExcludeSelf && packageName != YukiHookBridge.modulePackageName)
+ (isExcludeSelf.not() || isExcludeSelf && packageName != modulePackageName)
) initiate(this)
}
@@ -307,7 +320,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
*/
fun loadApp(isExcludeSelf: Boolean = false, hooker: YukiBaseHooker) {
if (wrapper?.type != HookEntryType.ZYGOTE &&
- (isExcludeSelf.not() || isExcludeSelf && packageName != YukiHookBridge.modulePackageName)
+ (isExcludeSelf.not() || isExcludeSelf && packageName != modulePackageName)
) loadHooker(hooker)
}
@@ -323,7 +336,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
fun loadApp(isExcludeSelf: Boolean = false, vararg hooker: YukiBaseHooker) {
if (hooker.isEmpty()) error("loadApp method need a \"hooker\" param")
if (wrapper?.type != HookEntryType.ZYGOTE &&
- (isExcludeSelf.not() || isExcludeSelf && packageName != YukiHookBridge.modulePackageName)
+ (isExcludeSelf.not() || isExcludeSelf && packageName != modulePackageName)
) hooker.forEach { loadHooker(it) }
}
@@ -331,13 +344,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 装载并 Hook 系统框架
* @param initiate 方法体
*/
- inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, initiate)
+ inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(SYSTEM_FRAMEWORK_NAME, initiate)
/**
* 装载并 Hook 系统框架
* @param hooker Hook 子类
*/
- fun loadSystem(hooker: YukiBaseHooker) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, hooker)
+ fun loadSystem(hooker: YukiBaseHooker) = loadApp(SYSTEM_FRAMEWORK_NAME, hooker)
/**
* 装载并 Hook 系统框架
@@ -345,7 +358,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
*/
fun loadSystem(vararg hooker: YukiBaseHooker) {
if (hooker.isEmpty()) error("loadSystem method need a \"hooker\" param")
- loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, *hooker)
+ loadApp(SYSTEM_FRAMEWORK_NAME, *hooker)
}
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/PackageParamWrapper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/PackageParamWrapper.kt
index d2ac89e3..a69f31a6 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/PackageParamWrapper.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/wrapper/PackageParamWrapper.kt
@@ -30,16 +30,13 @@
package com.highcapable.yukihookapi.hook.param.wrapper
import android.content.pm.ApplicationInfo
-import com.highcapable.yukihookapi.annotation.YukiPrivateApi
import com.highcapable.yukihookapi.hook.param.PackageParam
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
import dalvik.system.PathClassLoader
/**
* 用于包装 [PackageParam]
- *
- * - ❗这是一个私有 API - 请不要在外部使用
* @param type 当前正在进行的 Hook 类型
* @param packageName 包名
* @param processName 当前进程名
@@ -47,8 +44,8 @@ import dalvik.system.PathClassLoader
* @param appInfo APP [ApplicationInfo]
* @param appResources APP [YukiResources]
*/
-@YukiPrivateApi
-class PackageParamWrapper internal constructor(
+@PublishedApi
+internal class PackageParamWrapper internal constructor(
var type: HookEntryType,
var packageName: String,
var processName: String,
@@ -68,5 +65,5 @@ class PackageParamWrapper internal constructor(
internal val isCorrectProcess get() = type == HookEntryType.ZYGOTE || (type != HookEntryType.ZYGOTE && appClassLoader is PathClassLoader)
override fun toString() =
- "PackageParamWrapper [type] $type [packageName] $packageName [processName] $processName [appInfo] $appInfo [appResources] $appResources"
+ "[type] $type [packageName] $packageName [processName] $processName [appClassLoader] $appClassLoader [appInfo] $appInfo [appResources] $appResources"
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt
deleted file mode 100644
index 4e28df27..00000000
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt
+++ /dev/null
@@ -1,279 +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 fankes on 2022/4/3.
- */
-@file:Suppress("unused", "StaticFieldLeak")
-
-package com.highcapable.yukihookapi.hook.xposed.bridge
-
-import android.content.pm.ApplicationInfo
-import com.highcapable.yukihookapi.YukiHookAPI
-import com.highcapable.yukihookapi.annotation.YukiGenerateApi
-import com.highcapable.yukihookapi.hook.factory.classOf
-import com.highcapable.yukihookapi.hook.factory.field
-import com.highcapable.yukihookapi.hook.factory.hasClass
-import com.highcapable.yukihookapi.hook.log.yLoggerE
-import com.highcapable.yukihookapi.hook.param.PackageParam
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType
-import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
-import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
-import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
-import dalvik.system.PathClassLoader
-import de.robv.android.xposed.IXposedHookInitPackageResources
-import de.robv.android.xposed.IXposedHookLoadPackage
-import de.robv.android.xposed.IXposedHookZygoteInit
-import de.robv.android.xposed.XposedBridge
-import de.robv.android.xposed.callbacks.XC_InitPackageResources
-import de.robv.android.xposed.callbacks.XC_LoadPackage
-
-/**
- * 这是一个对接 Xposed Hook 入口与 [XposedBridge] 的装载类实现桥
- *
- * 实现与 [IXposedHookZygoteInit]、[IXposedHookLoadPackage]、[IXposedHookInitPackageResources] 接口通讯
- *
- * - ❗装载代码将自动生成 - 请勿修改或移动以及重命名此类的任何方法与变量
- */
-@YukiGenerateApi
-object YukiHookBridge {
-
- /** Android 系统框架名称 */
- @PublishedApi
- internal const val SYSTEM_FRAMEWORK_NAME = "android"
-
- /** Xposed 是否装载完成 */
- private var isXposedInitialized = false
-
- /** 当前 Hook 进程是否正处于 [IXposedHookZygoteInit.initZygote] */
- private var isInitializingZygote = false
-
- /** 已在 [PackageParam] 中被装载的 APP 包名 */
- private val loadedPackageNames = HashSet()
-
- /** 当前 [PackageParamWrapper] 实例数组 */
- private val packageParamWrappers = HashMap()
-
- /** 当前 [PackageParam] 方法体回调 */
- internal var packageParamCallback: (PackageParam.() -> Unit)? = null
-
- /** 当前 Hook Framework 是否支持 Resources Hook */
- internal var isSupportResourcesHook = false
-
- /**
- * 当前宿主正在进行的 Hook 进程标识名称
- * @return [String]
- */
- internal val hostProcessName get() = if (isInitializingZygote) "android-zygote" else YukiHookAppHelper.currentPackageName() ?: "unknown"
-
- /**
- * 获取项目编译完成的时间戳 (当前本地时间)
- * @return [Long]
- */
- internal val compiledTimestamp get() = runCatching { YukiHookBridge_Impl.compiledTimestamp }.getOrNull() ?: 0L
-
- /**
- * 自动生成的 Xposed 模块构建版本号
- *
- * 获取 [compiledTimestamp] 并转换为字符串
- * @return [String]
- */
- internal val moduleGeneratedVersion get() = compiledTimestamp.toString()
-
- /**
- * 预设的 Xposed 模块包名
- *
- * - ❗装载代码将自动生成 - 请勿手动修改 - 会引发未知异常
- */
- @YukiGenerateApi
- var modulePackageName = ""
-
- /**
- * 模块是否装载了 Xposed 回调方法
- *
- * - ❗装载代码将自动生成 - 请勿手动修改 - 会引发未知异常
- * @return [Boolean]
- */
- @YukiGenerateApi
- val isXposedCallbackSetUp
- get() = isXposedInitialized.not() && packageParamCallback != null
-
- /**
- * 获取当前 Hook 框架的名称
- *
- * 从 [XposedBridge] 获取 TAG
- * @return [String] 无法获取会返回 unknown - [hasXposedBridge] 不存在会返回 invalid
- */
- internal val executorName
- get() = runCatching {
- if (YukiHookModuleStatus.EXPOSED_BRIDGE_CLASS_NAME.hasClass(YukiHookAppHelper.currentApplication()?.classLoader))
- YukiHookModuleStatus.TAICHI_XPOSED_NAME
- else classOf().field { name = "TAG" }.ignored().get().string().takeIf { it.isNotBlank() }
- ?.replace("Bridge", "")?.replace("-", "")?.trim() ?: "unknown"
- }.getOrNull() ?: "invalid"
-
- /**
- * 获取当前 Hook 框架的版本
- *
- * 获取 [XposedBridge.getXposedVersion]
- * @return [Int] 无法获取会返回 -1
- */
- internal val executorVersion get() = runCatching { XposedBridge.getXposedVersion() }.getOrNull() ?: -1
-
- /**
- * 是否存在 [XposedBridge]
- * @return [Boolean]
- */
- internal val hasXposedBridge get() = executorVersion >= 0
-
- /**
- * 自动忽略 MIUI 系统可能出现的日志收集注入实例
- * @param packageName 当前包名
- * @return [Boolean] 是否存在
- */
- private fun isMiuiCatcherPatch(packageName: String?) =
- (packageName == "com.miui.contentcatcher" || packageName == "com.miui.catcherpatch") && "android.miui.R".hasClass()
-
- /**
- * 当前包名是否已在指定的 [HookEntryType] 被装载
- * @param packageName 包名
- * @param type 当前 Hook 类型
- * @return [Boolean] 是否已被装载
- */
- private fun isPackageLoaded(packageName: String, type: HookEntryType): Boolean {
- if (loadedPackageNames.contains("$packageName:$type")) return true
- loadedPackageNames.add("$packageName:$type")
- return false
- }
-
- /**
- * 创建、修改 [PackageParamWrapper]
- *
- * 忽略在 [type] 不为 [HookEntryType.ZYGOTE] 时 [appClassLoader] 为空导致首次使用 [XposedBridge.BOOTCLASSLOADER] 装载的问题
- * @param type 当前正在进行的 Hook 类型
- * @param packageName 包名
- * @param processName 当前进程名
- * @param appClassLoader APP [ClassLoader]
- * @param appInfo APP [ApplicationInfo]
- * @param appResources APP [YukiResources]
- * @return [PackageParamWrapper] or null
- */
- private fun assignWrapper(
- type: HookEntryType,
- packageName: String?,
- processName: String? = "",
- appClassLoader: ClassLoader? = null,
- appInfo: ApplicationInfo? = null,
- appResources: YukiResources? = null
- ) = run {
- isInitializingZygote = type == HookEntryType.ZYGOTE
- if (packageParamWrappers[packageName] == null)
- if (type == HookEntryType.ZYGOTE || appClassLoader != null)
- PackageParamWrapper(
- type = type,
- packageName = packageName ?: SYSTEM_FRAMEWORK_NAME,
- processName = processName ?: SYSTEM_FRAMEWORK_NAME,
- appClassLoader = appClassLoader ?: XposedBridge.BOOTCLASSLOADER,
- appInfo = appInfo,
- appResources = appResources
- ).also { packageParamWrappers[packageName ?: SYSTEM_FRAMEWORK_NAME] = it }
- else null
- else packageParamWrappers[packageName]?.also { wrapper ->
- wrapper.type = type
- packageName?.takeIf { it.isNotBlank() }?.also { wrapper.packageName = it }
- processName?.takeIf { it.isNotBlank() }?.also { wrapper.processName = it }
- appClassLoader?.takeIf { type == HookEntryType.ZYGOTE || it is PathClassLoader }?.also { wrapper.appClassLoader = it }
- appInfo?.also { wrapper.appInfo = it }
- appResources?.also { wrapper.appResources = it }
- }
- }
-
- /**
- * 标识 Xposed API 装载完成
- *
- * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
- */
- @YukiGenerateApi
- fun callXposedInitialized() {
- isXposedInitialized = true
- }
-
- /**
- * 装载 Xposed API Zygote 回调
- *
- * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
- * @param sparam Xposed [IXposedHookZygoteInit.StartupParam]
- */
- @YukiGenerateApi
- fun callXposedZygoteLoaded(sparam: IXposedHookZygoteInit.StartupParam) {
- AppParasitics.moduleAppFilePath = sparam.modulePath
- AppParasitics.refreshModuleAppResources()
- }
-
- /**
- * 装载 Xposed API 回调
- *
- * 这里的入口会装载三次
- *
- * - 在 [IXposedHookZygoteInit.initZygote] 时装载
- *
- * - 在 [IXposedHookLoadPackage.handleLoadPackage] 时装载
- *
- * - 在 [IXposedHookInitPackageResources.handleInitPackageResources] 时装载
- *
- * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed API 事件
- * @param isZygoteLoaded 是否为 Xposed [IXposedHookZygoteInit.initZygote]
- * @param lpparam Xposed [XC_LoadPackage.LoadPackageParam]
- * @param resparam Xposed [XC_InitPackageResources.InitPackageResourcesParam]
- */
- @YukiGenerateApi
- fun callXposedLoaded(
- isZygoteLoaded: Boolean,
- lpparam: XC_LoadPackage.LoadPackageParam? = null,
- resparam: XC_InitPackageResources.InitPackageResourcesParam? = null
- ) {
- if (isMiuiCatcherPatch(packageName = lpparam?.packageName ?: resparam?.packageName).not()) when {
- isZygoteLoaded -> assignWrapper(HookEntryType.ZYGOTE, SYSTEM_FRAMEWORK_NAME, SYSTEM_FRAMEWORK_NAME)
- lpparam != null ->
- if (isPackageLoaded(lpparam.packageName, HookEntryType.PACKAGE).not())
- assignWrapper(HookEntryType.PACKAGE, lpparam.packageName, lpparam.processName, lpparam.classLoader, lpparam.appInfo)
- else null
- resparam != null ->
- if (isPackageLoaded(resparam.packageName, HookEntryType.RESOURCES).not())
- assignWrapper(HookEntryType.RESOURCES, resparam.packageName, appResources = YukiResources.wrapper(resparam.res))
- else null
- else -> null
- }?.also {
- runCatching {
- if (it.isCorrectProcess) YukiHookAPI.onXposedLoaded(it)
- if (it.type != HookEntryType.ZYGOTE && it.packageName == modulePackageName)
- AppParasitics.hookModuleAppRelated(it.appClassLoader, it.type)
- if (it.type == HookEntryType.PACKAGE) AppParasitics.registerToAppLifecycle(it.packageName)
- if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true
- }.onFailure { yLoggerE(msg = "An exception occurred in the Hooking Process of YukiHookAPI", e = it) }
- }
- }
-}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiXposedModule.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiXposedModule.kt
new file mode 100644
index 00000000..1b1a2887
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiXposedModule.kt
@@ -0,0 +1,217 @@
+/*
+ * 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/4/3.
+ * This file is Modified by fankes on 2023/1/9.
+ */
+package com.highcapable.yukihookapi.hook.xposed.bridge
+
+import android.content.pm.ApplicationInfo
+import android.content.res.Resources
+import com.highcapable.yukihookapi.YukiHookAPI
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
+import com.highcapable.yukihookapi.hook.factory.hasClass
+import com.highcapable.yukihookapi.hook.log.yLoggerE
+import com.highcapable.yukihookapi.hook.param.PackageParam
+import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
+import com.highcapable.yukihookapi.hook.xposed.bridge.proxy.IYukiXposedModuleLifecycle
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiModuleResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
+import dalvik.system.PathClassLoader
+
+/**
+ * Xposed 模块核心功能实现类
+ */
+internal object YukiXposedModule : IYukiXposedModuleLifecycle {
+
+ /** Xposed 模块是否已被装载 */
+ private var isModuleLoaded = false
+
+ /** Xposed 模块是否装载完成 */
+ private var isModuleLoadFinished = false
+
+ /** 当前 Hook 进程是否正处于 Zygote */
+ private var isInitializingZygote = false
+
+ /** 当前 [PackageParam] 实例 */
+ private val packageParam = PackageParam()
+
+ /** 已在 [PackageParam] 中被装载的 APP 包名 */
+ private val loadedPackageNames = HashSet()
+
+ /** 当前 [PackageParamWrapper] 实例数组 */
+ private val packageParamWrappers = HashMap()
+
+ /** 当前 [PackageParam] 方法体回调 */
+ internal var packageParamCallback: (PackageParam.() -> Unit)? = null
+
+ /** 当前 Hook Framework 是否支持 Resources Hook */
+ internal var isSupportResourcesHook = false
+
+ /** 预设的 Xposed 模块包名 */
+ internal var modulePackageName = ""
+
+ /** 当前 Xposed 模块自身 APK 路径 */
+ internal var moduleAppFilePath = ""
+
+ /** 当前 Xposed 模块自身 [Resources] */
+ internal var moduleAppResources: YukiModuleResources? = null
+
+ /**
+ * 获取当前 Xposed 模块自身动态 [Resources]
+ * @return [YukiModuleResources] or null
+ */
+ internal val dynamicModuleAppResources get() = runCatching { YukiModuleResources.wrapper(moduleAppFilePath) }.getOrNull()
+
+ /**
+ * 模块是否装载了 Xposed 回调方法
+ * @return [Boolean]
+ */
+ internal val isXposedCallbackSetUp get() = isModuleLoadFinished.not() && packageParamCallback != null
+
+ /**
+ * 当前宿主正在进行的 Hook 进程标识名称
+ * @return [String]
+ */
+ internal val hostProcessName get() = if (isInitializingZygote) "android-zygote" else AppParasitics.currentPackageName
+
+ /**
+ * 获取当前是否为 (Xposed) 宿主环境
+ * @return [Boolean]
+ */
+ internal val isXposedEnvironment get() = HookApiCategoryHelper.hasAvailableHookApi && isModuleLoaded
+
+ /**
+ * 自动忽略 MIUI 系统可能出现的日志收集注入实例
+ * @param packageName 当前包名
+ * @return [Boolean] 是否存在
+ */
+ private fun isMiuiCatcherPatch(packageName: String?) =
+ (packageName == "com.miui.contentcatcher" || packageName == "com.miui.catcherpatch") && "android.miui.R".hasClass()
+
+ /**
+ * 当前包名是否已在指定的 [HookEntryType] 被装载
+ * @param packageName 包名
+ * @param type 当前 Hook 类型
+ * @return [Boolean] 是否已被装载
+ */
+ private fun isPackageLoaded(packageName: String?, type: HookEntryType): Boolean {
+ if (packageName == null) return false
+ if (loadedPackageNames.contains("$packageName:$type")) return true
+ loadedPackageNames.add("$packageName:$type")
+ return false
+ }
+
+ /**
+ * 创建、修改 [PackageParamWrapper]
+ *
+ * 忽略在 [type] 不为 [HookEntryType.ZYGOTE] 时 [appClassLoader] 为空导致首次使用 [ClassLoader.getSystemClassLoader] 装载的问题
+ * @param type 当前正在进行的 Hook 类型
+ * @param packageName 包名
+ * @param processName 当前进程名
+ * @param appClassLoader APP [ClassLoader]
+ * @param appInfo APP [ApplicationInfo]
+ * @param appResources APP [YukiResources]
+ * @return [PackageParamWrapper] or null
+ */
+ private fun assignWrapper(
+ type: HookEntryType,
+ packageName: String?,
+ processName: String? = "",
+ appClassLoader: ClassLoader? = null,
+ appInfo: ApplicationInfo? = null,
+ appResources: YukiResources? = null
+ ) = run {
+ isInitializingZygote = type == HookEntryType.ZYGOTE
+ if (packageParamWrappers[packageName] == null)
+ if (type == HookEntryType.ZYGOTE || appClassLoader != null)
+ PackageParamWrapper(
+ type = type,
+ packageName = packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME,
+ processName = processName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME,
+ appClassLoader = appClassLoader ?: ClassLoader.getSystemClassLoader(),
+ appInfo = appInfo,
+ appResources = appResources
+ ).also { packageParamWrappers[packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME] = it }
+ else null
+ else packageParamWrappers[packageName]?.also { wrapper ->
+ wrapper.type = type
+ packageName?.takeIf { it.isNotBlank() }?.also { wrapper.packageName = it }
+ processName?.takeIf { it.isNotBlank() }?.also { wrapper.processName = it }
+ appClassLoader?.takeIf { type == HookEntryType.ZYGOTE || it is PathClassLoader }?.also { wrapper.appClassLoader = it }
+ appInfo?.also { wrapper.appInfo = it }
+ appResources?.also { wrapper.appResources = it }
+ }
+ }
+
+ /** 刷新当前 Xposed 模块自身 [Resources] */
+ internal fun refreshModuleAppResources() {
+ dynamicModuleAppResources?.let { moduleAppResources = it }
+ }
+
+ override fun onStartLoadModule(packageName: String, appFilePath: String) {
+ isModuleLoaded = true
+ modulePackageName = packageName
+ moduleAppFilePath = appFilePath
+ refreshModuleAppResources()
+ }
+
+ override fun onFinishLoadModule() {
+ isModuleLoadFinished = true
+ }
+
+ override fun onPackageLoaded(
+ type: HookEntryType,
+ packageName: String?,
+ processName: String?,
+ appClassLoader: ClassLoader?,
+ appInfo: ApplicationInfo?,
+ appResources: YukiResources?
+ ) {
+ if (isMiuiCatcherPatch(packageName).not()) when (type) {
+ HookEntryType.ZYGOTE ->
+ assignWrapper(HookEntryType.ZYGOTE, AppParasitics.SYSTEM_FRAMEWORK_NAME, AppParasitics.SYSTEM_FRAMEWORK_NAME, appClassLoader)
+ HookEntryType.PACKAGE ->
+ if (isPackageLoaded(packageName, HookEntryType.PACKAGE).not())
+ assignWrapper(HookEntryType.PACKAGE, packageName, processName, appClassLoader, appInfo)
+ else null
+ HookEntryType.RESOURCES ->
+ /** 这里可能会出现 [packageName] 获取到非实际宿主的问题 - 如果包名与 [AppParasitics.currentPackageName] 不相同这里做忽略处理 */
+ if (isPackageLoaded(packageName, HookEntryType.RESOURCES).not() && packageName == AppParasitics.currentPackageName)
+ assignWrapper(HookEntryType.RESOURCES, packageName, appResources = appResources)
+ else null
+ }?.also {
+ runCatching {
+ if (it.isCorrectProcess) packageParamCallback?.invoke(packageParam.assign(it).apply { YukiHookAPI.printSplashInfo() })
+ if (it.type != HookEntryType.ZYGOTE && it.packageName == modulePackageName)
+ AppParasitics.hookModuleAppRelated(it.appClassLoader, it.type)
+ if (it.type == HookEntryType.PACKAGE) AppParasitics.registerToAppLifecycle(it.packageName)
+ if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true
+ }.onFailure { yLoggerE(msg = "An exception occurred in the Hooking Process of YukiHookAPI", e = it) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/caller/YukiXposedModuleCaller.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/caller/YukiXposedModuleCaller.kt
new file mode 100644
index 00000000..ab0b2543
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/caller/YukiXposedModuleCaller.kt
@@ -0,0 +1,104 @@
+/*
+ * 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 2023/1/9.
+ */
+@file:Suppress("unused")
+
+package com.highcapable.yukihookapi.hook.xposed.bridge.caller
+
+import android.content.pm.ApplicationInfo
+import com.highcapable.yukihookapi.annotation.YukiGenerateApi
+import com.highcapable.yukihookapi.hook.log.yLoggerE
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
+
+/**
+ * Xposed 模块核心功能调用类
+ *
+ * - ❗装载代码将自动生成 - 请勿手动调用
+ */
+@YukiGenerateApi
+object YukiXposedModuleCaller {
+
+ /**
+ * 模块是否装载了 Xposed 回调方法
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @return [Boolean]
+ */
+ @YukiGenerateApi
+ val isXposedCallbackSetUp get() = YukiXposedModule.isXposedCallbackSetUp
+
+ /**
+ * 标识 Xposed 模块开始装载
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @param packageName 当前 Xposed 模块包名
+ * @param appFilePath 当前 Xposed 模块自身 APK 路径
+ */
+ @YukiGenerateApi
+ fun callOnStartLoadModule(packageName: String, appFilePath: String) = YukiXposedModule.onStartLoadModule(packageName, appFilePath)
+
+ /**
+ * 标识 Xposed 模块装载完成
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ */
+ @YukiGenerateApi
+ fun callOnFinishLoadModule() = YukiXposedModule.onFinishLoadModule()
+
+ /**
+ * 标识可用的 Hook APP (宿主) 开始装载
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @param type 当前正在进行的 Hook 类型
+ * @param packageName 宿主包名
+ * @param processName 宿主进程名
+ * @param appClassLoader 宿主 [ClassLoader]
+ * @param appInfo 宿主 [ApplicationInfo]
+ * @param appResources 宿主 [YukiResources]
+ */
+ @YukiGenerateApi
+ fun callOnPackageLoaded(
+ type: HookEntryType,
+ packageName: String?,
+ processName: String? = "",
+ appClassLoader: ClassLoader? = null,
+ appInfo: ApplicationInfo? = null,
+ appResources: YukiResources? = null
+ ) = YukiXposedModule.onPackageLoaded(type, packageName, processName, appClassLoader, appInfo, appResources)
+
+ /**
+ * 打印内部 E 级别的日志
+ *
+ * - ❗装载代码将自动生成 - 请勿手动调用
+ * @param msg 日志打印的内容
+ * @param e 异常堆栈信息 - 默认空
+ */
+ @YukiGenerateApi
+ fun internalLoggerE(msg: String, e: Throwable? = null) = yLoggerE(msg = msg, e = e)
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.kt
index 32f23faa..2eccdc99 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.kt
@@ -24,12 +24,12 @@
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/30.
+ * This file is Modified by fankes on 2022/1/10.
*/
@file:Suppress("unused")
package com.highcapable.yukihookapi.hook.xposed.bridge.event
-import com.highcapable.yukihookapi.annotation.YukiGenerateApi
import de.robv.android.xposed.IXposedHookZygoteInit.StartupParam
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
@@ -40,13 +40,13 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
object YukiXposedEvent {
/** 监听 initZygote 开始的回调方法 */
- private var initZygoteCallback: ((StartupParam) -> Unit)? = null
+ internal var initZygoteCallback: ((StartupParam) -> Unit)? = null
/** 监听 handleLoadPackage 开始的回调方法 */
- private var handleLoadPackageCallback: ((LoadPackageParam) -> Unit)? = null
+ internal var handleLoadPackageCallback: ((LoadPackageParam) -> Unit)? = null
/** 监听 handleInitPackageResources 开始的回调方法 */
- private var handleInitPackageResourcesCallback: ((InitPackageResourcesParam) -> Unit)? = null
+ internal var handleInitPackageResourcesCallback: ((InitPackageResourcesParam) -> Unit)? = null
/**
* 对 [YukiXposedEvent] 创建一个方法体
@@ -79,49 +79,4 @@ object YukiXposedEvent {
fun onHandleInitPackageResources(result: (InitPackageResourcesParam) -> Unit) {
handleInitPackageResourcesCallback = result
}
-
- /**
- * 回调监听事件处理类
- *
- * - ❗装载代码将自动生成 - 请勿手动调用
- */
- @YukiGenerateApi
- object EventHandler {
-
- /**
- * 回调 initZygote 事件监听
- *
- * - ❗装载代码将自动生成 - 请勿手动调用
- * @param sparam Xposed API 实例
- */
- @YukiGenerateApi
- fun callInitZygote(sparam: StartupParam?) {
- if (sparam == null) return
- initZygoteCallback?.invoke(sparam)
- }
-
- /**
- * 回调 handleLoadPackage 事件监听
- *
- * - ❗装载代码将自动生成 - 请勿手动调用
- * @param lpparam Xposed API 实例
- */
- @YukiGenerateApi
- fun callHandleLoadPackage(lpparam: LoadPackageParam?) {
- if (lpparam == null) return
- handleLoadPackageCallback?.invoke(lpparam)
- }
-
- /**
- * 回调 handleInitPackageResources 事件监听
- *
- * - ❗装载代码将自动生成 - 请勿手动调用
- * @param resparam Xposed API 实例
- */
- @YukiGenerateApi
- fun callHandleInitPackageResources(resparam: InitPackageResourcesParam?) {
- if (resparam == null) return
- handleInitPackageResourcesCallback?.invoke(resparam)
- }
- }
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/caller/YukiXposedEventCaller.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/caller/YukiXposedEventCaller.kt
new file mode 100644
index 00000000..810b0d2d
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/event/caller/YukiXposedEventCaller.kt
@@ -0,0 +1,81 @@
+/*
+ * 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/1/10.
+ */
+@file:Suppress("unused")
+
+package com.highcapable.yukihookapi.hook.xposed.bridge.event.caller
+
+import com.highcapable.yukihookapi.annotation.YukiGenerateApi
+import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent
+import de.robv.android.xposed.IXposedHookZygoteInit
+import de.robv.android.xposed.callbacks.XC_InitPackageResources
+import de.robv.android.xposed.callbacks.XC_LoadPackage
+
+/**
+ * 实现对原生 Xposed API 装载事件监听的回调监听事件处理类
+ *
+ * - ❗装载代码将自动生成 - 请勿手动调用
+ */
+@YukiGenerateApi
+object YukiXposedEventCaller {
+
+ /**
+ * 回调 initZygote 事件监听
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @param sparam Xposed API 实例
+ */
+ @YukiGenerateApi
+ fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {
+ if (sparam == null) return
+ YukiXposedEvent.initZygoteCallback?.invoke(sparam)
+ }
+
+ /**
+ * 回调 handleLoadPackage 事件监听
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @param lpparam Xposed API 实例
+ */
+ @YukiGenerateApi
+ fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
+ if (lpparam == null) return
+ YukiXposedEvent.handleLoadPackageCallback?.invoke(lpparam)
+ }
+
+ /**
+ * 回调 handleInitPackageResources 事件监听
+ *
+ * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
+ * @param resparam Xposed API 实例
+ */
+ @YukiGenerateApi
+ fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {
+ if (resparam == null) return
+ YukiXposedEvent.handleInitPackageResourcesCallback?.invoke(resparam)
+ }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/factory/YukiBridgeFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/factory/YukiBridgeFactory.kt
deleted file mode 100644
index 18201fef..00000000
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/factory/YukiBridgeFactory.kt
+++ /dev/null
@@ -1,299 +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 fankes on 2022/7/28.
- */
-package com.highcapable.yukihookapi.hook.xposed.bridge.factory
-
-import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
-import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder
-import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
-import com.highcapable.yukihookapi.hook.log.yLoggerE
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import de.robv.android.xposed.XC_MethodHook
-import de.robv.android.xposed.XposedBridge
-import de.robv.android.xposed.XposedHelpers
-import java.lang.reflect.Member
-
-/**
- * Hook 回调优先级配置类
- */
-internal object YukiHookPriority {
-
- /** 默认 Hook 回调优先级 */
- internal const val PRIORITY_DEFAULT = 50
-
- /** 延迟回调 Hook 方法结果 */
- internal const val PRIORITY_LOWEST = -10000
-
- /** 更快回调 Hook 方法结果 */
- internal const val PRIORITY_HIGHEST = 10000
-}
-
-/**
- * 已经 Hook 的方法、构造方法缓存数组
- */
-internal object YukiHookedMembers {
-
- /** 已经 Hook 的 [Member] 数组 */
- internal val hookedMembers = HashSet()
-}
-
-/**
- * Hook 核心功能实现实例
- *
- * 对接 [XposedBridge] 实现 Hook 功能
- */
-internal object YukiHookHelper {
-
- /**
- * 使用 [XposedHelpers.findClass] 来查找 [Class]
- * @param name [Class] 的完整包名+名称
- * @param loader [Class] 所在的 [ClassLoader] - 默认空 - 可不填
- * @return [Class] or null
- * @throws ClassNotFoundException 如果找不到 [Class]
- */
- internal fun findClass(name: String, loader: ClassLoader? = null) =
- if (YukiHookBridge.hasXposedBridge) XposedHelpers.findClass(name, loader) else null
-
- /**
- * Hook [BaseFinder.BaseResult]
- * @param traction 直接调用 [BaseFinder.BaseResult]
- * @param callback 回调
- * @return [Pair] - ([YukiMemberHook.Unhook] or null,[Boolean] 是否已经 Hook)
- */
- internal fun hook(traction: BaseFinder.BaseResult, callback: YukiHookCallback) = runCatching {
- val member: Member? = when (traction) {
- is MethodFinder.Result -> traction.ignored().give()
- is ConstructorFinder.Result -> traction.ignored().give()
- else -> error("Unexpected BaseFinder result interface type")
- }
- hookMember(member, callback)
- }.onFailure { yLoggerE(msg = "An exception occurred when hooking internal function", e = it) }.getOrNull() ?: Pair(null, false)
-
- /**
- * Hook [Member]
- *
- * 对接 [XposedBridge.hookMethod]
- * @param member 需要 Hook 的方法、构造方法
- * @param callback 回调
- * @return [Pair] - ([YukiMemberHook.Unhook] or null,[Boolean] 是否已经 Hook)
- */
- internal fun hookMember(member: Member?, callback: YukiHookCallback): Pair {
- runCatching {
- YukiHookedMembers.hookedMembers.takeIf { it.isNotEmpty() }?.forEach {
- if (it.member.toString() == member?.toString()) return@runCatching it
- }
- }
- return when {
- member == null -> Pair(null, false)
- YukiHookBridge.hasXposedBridge ->
- XposedBridge.hookMethod(member, callback.compat()).compat().let { memberUnhook ->
- YukiHookedMembers.hookedMembers.add(memberUnhook)
- Pair(memberUnhook, false)
- }
- else -> Pair(null, false)
- }
- }
-
- /**
- * 执行原始 [Member]
- *
- * 未进行 Hook 的 [Member]
- * @param member 实例
- * @param args 参数实例
- * @return [Any] or null
- */
- internal fun invokeOriginalMember(member: Member?, instance: Any?, vararg args: Any?) =
- if (YukiHookBridge.hasXposedBridge && YukiHookedMembers.hookedMembers.any { it.member.toString() == member.toString() })
- member?.let {
- runCatching { XposedBridge.invokeOriginalMethod(it, instance, args) }
- .onFailure { yLoggerE(msg = "Invoke original Member [$member] failed", e = it) }
- .getOrNull()
- }
- else null
-
- /**
- * 兼容对接已 Hook 的 [Member] 接口
- * @return [YukiMemberHook.Unhook]
- */
- private fun XC_MethodHook.Unhook.compat() = object : YukiMemberHook.Unhook() {
- override val member get() = hookedMethod
- override fun unhook() = this@compat.unhook()
- }
-
- /**
- * 兼容对接 Hook 回调接口
- * @return [XC_MethodHook] 原始接口
- */
- private fun YukiHookCallback.compat() = object : XC_MethodHook(priority) {
-
- override fun beforeHookedMethod(param: MethodHookParam?) {
- if (param == null) return
- if (this@compat !is YukiMemberHook) error("Invalid YukiHookCallback type")
- if (this@compat is YukiMemberReplacement)
- param.result = replaceHookedMember(param.compat())
- else beforeHookedMember(param.compat())
- }
-
- override fun afterHookedMethod(param: MethodHookParam?) {
- if (param == null) return
- if (this@compat !is YukiMemberHook) error("Invalid YukiHookCallback type")
- afterHookedMember(param.compat())
- }
- }
-
- /**
- * 兼容对接 Hook 结果回调接口
- * @return [YukiHookCallback.Param]
- */
- private fun XC_MethodHook.MethodHookParam.compat() = object : YukiHookCallback.Param {
- override val member get() = this@compat.method
- override val instance get() = this@compat.thisObject
- override val args get() = this@compat.args
- override val hasThrowable get() = this@compat.hasThrowable()
- override var result
- get() = this@compat.result
- set(value) {
- this@compat.result = value
- }
- override var throwable
- get() = this@compat.throwable
- set(value) {
- this@compat.throwable = value
- }
- }
-}
-
-/**
- * Hook 替换方法回调接口抽象类
- * @param priority Hook 优先级- 默认 [YukiHookPriority.PRIORITY_DEFAULT]
- */
-internal abstract class YukiMemberReplacement(override val priority: Int = YukiHookPriority.PRIORITY_DEFAULT) : YukiMemberHook(priority) {
-
- override fun beforeHookedMember(param: Param) {
- param.result = replaceHookedMember(param)
- }
-
- override fun afterHookedMember(param: Param) {}
-
- /**
- * 拦截替换为指定结果
- * @param param Hook 结果回调接口
- * @return [Any] or null
- */
- abstract fun replaceHookedMember(param: Param): Any?
-}
-
-/**
- * Hook 方法回调接口抽象类
- * @param priority Hook 优先级 - 默认 [YukiHookPriority.PRIORITY_DEFAULT]
- */
-internal abstract class YukiMemberHook(override val priority: Int = YukiHookPriority.PRIORITY_DEFAULT) : YukiHookCallback(priority) {
-
- /**
- * 在方法执行之前注入
- * @param param Hook 结果回调接口
- */
- open fun beforeHookedMember(param: Param) {}
-
- /**
- * 在方法执行之后注入
- * @param param Hook 结果回调接口
- */
- open fun afterHookedMember(param: Param) {}
-
- /**
- * 已经 Hook 且可被解除 Hook 的 [Member] 实现接口抽象类
- */
- internal abstract class Unhook internal constructor() {
-
- /**
- * 当前被 Hook 的 [Member]
- * @return [Member] or null
- */
- internal abstract val member: Member?
-
- /** 解除 Hook */
- internal abstract fun unhook()
-
- /** 解除 Hook 并从 [YukiHookedMembers.hookedMembers] 缓存数组中移除 */
- internal fun remove() {
- if (YukiHookBridge.hasXposedBridge.not()) return
- unhook()
- runCatching { YukiHookedMembers.hookedMembers.remove(this) }
- }
- }
-}
-
-/**
- * Hook 回调接口抽象类
- * @param priority Hook 优先级
- */
-internal abstract class YukiHookCallback(open val priority: Int) {
-
- /**
- * Hook 结果回调接口
- */
- internal interface Param {
-
- /**
- * [Member] 实例
- * @return [Member] or null
- */
- val member: Member?
-
- /**
- * 当前实例对象
- * @return [Any] or null
- */
- val instance: Any?
-
- /**
- * 方法、构造方法数组
- * @return [Array] or null
- */
- val args: Array?
-
- /**
- * 获取、设置方法结果
- * @return [Any] or null
- */
- var result: Any?
-
- /**
- * 判断是否存在设置过的方法调用抛出异常
- * @return [Boolean]
- */
- val hasThrowable: Boolean
-
- /**
- * 获取、设置方法调用抛出的异常
- * @return [Throwable] or null
- * @throws Throwable
- */
- var throwable: Throwable?
- }
-}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/proxy/IYukiXposedModuleLifecycle.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/proxy/IYukiXposedModuleLifecycle.kt
new file mode 100644
index 00000000..7fb132ce
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/proxy/IYukiXposedModuleLifecycle.kt
@@ -0,0 +1,66 @@
+/*
+ * 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 2023/1/11.
+ */
+package com.highcapable.yukihookapi.hook.xposed.bridge.proxy
+
+import android.content.pm.ApplicationInfo
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
+
+/**
+ * Xposed 模块生命周期实现接口
+ */
+internal interface IYukiXposedModuleLifecycle {
+
+ /**
+ * 当 Xposed 模块开始装载
+ * @param packageName 当前 Xposed 模块包名
+ * @param appFilePath 当前 Xposed 模块自身 APK 路径
+ */
+ fun onStartLoadModule(packageName: String, appFilePath: String)
+
+ /** 当 Xposed 模块装载完成 */
+ fun onFinishLoadModule()
+
+ /**
+ * 当可用的 Hook APP (宿主) 开始装载
+ * @param type 当前正在进行的 Hook 类型
+ * @param packageName 宿主包名
+ * @param processName 宿主进程名
+ * @param appClassLoader 宿主 [ClassLoader]
+ * @param appInfo 宿主 [ApplicationInfo]
+ * @param appResources 宿主 [YukiResources]
+ */
+ fun onPackageLoaded(
+ type: HookEntryType,
+ packageName: String?,
+ processName: String? = "",
+ appClassLoader: ClassLoader? = null,
+ appInfo: ApplicationInfo? = null,
+ appResources: YukiResources? = null
+ )
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiModuleResources.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.kt
similarity index 97%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiModuleResources.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.kt
index f11802e6..9876e9c2 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiModuleResources.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.kt
@@ -27,7 +27,7 @@
*/
@file:Suppress("DEPRECATION")
-package com.highcapable.yukihookapi.hook.xposed.bridge.dummy
+package com.highcapable.yukihookapi.hook.xposed.bridge.resources
import android.content.res.Resources
import android.content.res.XModuleResources
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResForwarder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.kt
similarity index 97%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResForwarder.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.kt
index 7acee0b7..e96e5901 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResForwarder.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.kt
@@ -27,7 +27,7 @@
*/
@file:Suppress("unused")
-package com.highcapable.yukihookapi.hook.xposed.bridge.dummy
+package com.highcapable.yukihookapi.hook.xposed.bridge.resources
import android.content.res.Resources
import android.content.res.XResForwarder
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResources.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.kt
similarity index 98%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResources.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.kt
index be365c78..fc3afb15 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/dummy/YukiResources.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.kt
@@ -27,14 +27,14 @@
*/
@file:Suppress("unused", "DEPRECATION", "DiscouragedApi")
-package com.highcapable.yukihookapi.hook.xposed.bridge.dummy
+package com.highcapable.yukihookapi.hook.xposed.bridge.resources
import android.content.res.Resources
import android.content.res.XResources
import android.graphics.drawable.Drawable
import android.view.View
import com.highcapable.yukihookapi.hook.log.yLoggerE
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources.LayoutInflatedParam
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources.LayoutInflatedParam
import de.robv.android.xposed.callbacks.XC_LayoutInflated
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/caller/YukiXposedResourcesCaller.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/caller/YukiXposedResourcesCaller.kt
new file mode 100644
index 00000000..aee81329
--- /dev/null
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/resources/caller/YukiXposedResourcesCaller.kt
@@ -0,0 +1,53 @@
+/*
+ * 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 2023/1/10.
+ */
+@file:Suppress("unused")
+
+package com.highcapable.yukihookapi.hook.xposed.bridge.resources.caller
+
+import android.content.res.XResources
+import com.highcapable.yukihookapi.annotation.YukiGenerateApi
+import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
+
+/**
+ * Xposed 模块资源钩子 (Resources Hook) 调用类
+ *
+ * - ❗装载代码将自动生成 - 请勿手动调用
+ */
+@YukiGenerateApi
+object YukiXposedResourcesCaller {
+
+ /**
+ * 从 [XResources] 创建 [YukiResources]
+ *
+ * - ❗装载代码将自动生成 - 请勿手动调用
+ * @param xResources [XResources] 实例
+ * @return [YukiResources] or null
+ */
+ @YukiGenerateApi
+ fun createYukiResourcesFromXResources(xResources: XResources?) = xResources?.let { YukiResources.wrapper(it) }
+}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus.kt
similarity index 62%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus.kt
index 3d9ae803..706e9cdd 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiXposedModuleStatus.kt
@@ -24,11 +24,11 @@
* SOFTWARE.
*
* This file is Created by fankes on 2022/2/3.
+ * This file is Modified by fankes on 2023/1/9.
*/
package com.highcapable.yukihookapi.hook.xposed.bridge.status
import com.highcapable.yukihookapi.YukiHookAPI
-import de.robv.android.xposed.XposedBridge
/**
* 这是一个 Xposed 模块 Hook 状态类
@@ -39,58 +39,23 @@ import de.robv.android.xposed.XposedBridge
*
* 调用 [YukiHookAPI.Status.isXposedModuleActive]
*
- * 你还可以使用以下方法获取当前 Hook 框架的详细信息
- *
- * 调用 [YukiHookAPI.Status.executorName] 来获取当前 Hook 框架的名称
- *
- * 调用 [YukiHookAPI.Status.executorVersion] 来获取当前 Hook 框架的版本
+ * 你还可以通过调用 [YukiHookAPI.Status.Executor] 获取当前 Hook 框架的详细信息
*
* 详情请参考 [Xposed 模块判断自身激活状态](https://fankes.github.io/YukiHookAPI/zh-cn/guide/example#xposed-%E6%A8%A1%E5%9D%97%E5%88%A4%E6%96%AD%E8%87%AA%E8%BA%AB%E6%BF%80%E6%B4%BB%E7%8A%B6%E6%80%81)
*
* For English version, see [Xposed Module own Active State](https://fankes.github.io/YukiHookAPI/en/guide/example#xposed-module-own-active-state)
*/
-internal object YukiHookModuleStatus {
+internal object YukiXposedModuleStatus {
- /** 定义 Jvm 方法名 */
internal const val IS_ACTIVE_METHOD_NAME = "__--"
-
- /** 定义 Jvm 方法名 */
internal const val IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME = "_--_"
+ internal const val GET_EXECUTOR_NAME_METHOD_NAME = "_-_-"
+ internal const val GET_EXECUTOR_API_LEVEL_METHOD_NAME = "-__-"
+ internal const val GET_EXECUTOR_VERSION_NAME_METHOD_NAME = "-_-_"
+ internal const val GET_EXECUTOR_VERSION_CODE_METHOD_NAME = "___-"
- /** 定义 Jvm 方法名 */
- internal const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
-
- /** 定义 Jvm 方法名 */
- internal const val GET_XPOSED_TAG_METHOD_NAME = "_-_-"
-
- /** TaiChi Xposed 框架名称 */
- internal const val TAICHI_XPOSED_NAME = "TaiChi"
-
- /** TaiChi ExposedBridge 完整类名 */
- internal const val EXPOSED_BRIDGE_CLASS_NAME = "me.weishu.exposed.ExposedBridge"
-
- /** [YukiHookModuleStatus_Impl] 完整类名 */
- internal const val IMPL_CLASS_NAME = "com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus_Impl"
-
- /**
- * 获取当前 Hook 框架的名称
- *
- * 从 [XposedBridge] 获取 TAG
- *
- * 请使用 [YukiHookAPI.Status.executorName] 获取
- * @return [String] 模块未激活会返回 unknown
- */
- internal val executorName get() = runCatching { YukiHookModuleStatus_Impl.getXposedBridgeTag() }.getOrNull() ?: "unknown"
-
- /**
- * 获取当前 Hook 框架的版本
- *
- * 获取 [XposedBridge.getXposedVersion]
- *
- * 请使用 [YukiHookAPI.Status.executorVersion] 获取
- * @return [Int] 模块未激活会返回 -1
- */
- internal val executorVersion get() = runCatching { YukiHookModuleStatus_Impl.getXposedVersion() }.getOrNull() ?: -1
+ /** [YukiXposedModuleStatus_Impl] 完整类名 */
+ internal const val IMPL_CLASS_NAME = "com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleStatus_Impl"
/**
* 获取当前模块的激活状态
@@ -98,7 +63,7 @@ internal object YukiHookModuleStatus {
* 请使用 [YukiHookAPI.Status.isModuleActive]、[YukiHookAPI.Status.isXposedModuleActive]、[YukiHookAPI.Status.isTaiChiModuleActive] 判断模块激活状态
* @return [Boolean]
*/
- internal val isActive get() = runCatching { YukiHookModuleStatus_Impl.isActive() }.getOrNull() ?: false
+ internal val isActive get() = runCatching { YukiXposedModuleStatus_Impl.isActive() }.getOrNull() ?: false
/**
* 获取当前 Hook Framework 是否支持资源钩子 (Resources Hook)
@@ -106,5 +71,37 @@ internal object YukiHookModuleStatus {
* 请使用 [YukiHookAPI.Status.isSupportResourcesHook] 判断支持状态
* @return [Boolean]
*/
- internal val isSupportResourcesHook get() = runCatching { YukiHookModuleStatus_Impl.isSupportResourcesHook() }.getOrNull() ?: false
+ internal val isSupportResourcesHook get() = runCatching { YukiXposedModuleStatus_Impl.isSupportResourcesHook() }.getOrNull() ?: false
+
+ /**
+ * 获取当前 Hook 框架的名称
+ *
+ * 请使用 [YukiHookAPI.Status.Executor.name] 获取
+ * @return [String] 模块未激活会返回 unknown
+ */
+ internal val executorName get() = runCatching { YukiXposedModuleStatus_Impl.getExecutorName() }.getOrNull() ?: "unknown"
+
+ /**
+ * 获取当前 Hook 框架的 API 版本
+ *
+ * 请使用 [YukiHookAPI.Status.Executor.apiLevel] 获取
+ * @return [Int] 模块未激活会返回 -1
+ */
+ internal val executorApiLevel get() = runCatching { YukiXposedModuleStatus_Impl.getExecutorApiLevel() }.getOrNull() ?: -1
+
+ /**
+ * 获取当前 Hook 框架的版本名称
+ *
+ * 请使用 [YukiHookAPI.Status.Executor.versionName] 获取
+ * @return [Int] 模块未激活会返回 unknown
+ */
+ internal val executorVersionName get() = runCatching { YukiXposedModuleStatus_Impl.getExecutorVersionName() }.getOrNull() ?: "unknown"
+
+ /**
+ * 获取当前 Hook 框架的版本号
+ *
+ * 请使用 [YukiHookAPI.Status.Executor.versionCode] 获取
+ * @return [Int] 模块未激活会返回 -1
+ */
+ internal val executorVersionCode get() = runCatching { YukiXposedModuleStatus_Impl.getExecutorVersionCode() }.getOrNull() ?: -1
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/type/HookEntryType.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/type/HookEntryType.kt
similarity index 68%
rename from yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/type/HookEntryType.kt
rename to yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/type/HookEntryType.kt
index 75dda8bc..442764f8 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/type/HookEntryType.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/type/HookEntryType.kt
@@ -24,33 +24,26 @@
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/26.
+ * This file is Modified by fankes on 2023/1/9.
*/
-package com.highcapable.yukihookapi.hook.param.type
+package com.highcapable.yukihookapi.hook.xposed.bridge.type
-import com.highcapable.yukihookapi.annotation.YukiPrivateApi
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType.*
-import de.robv.android.xposed.IXposedHookInitPackageResources
-import de.robv.android.xposed.IXposedHookLoadPackage
-import de.robv.android.xposed.IXposedHookZygoteInit
+import com.highcapable.yukihookapi.annotation.YukiGenerateApi
/**
* 当前正在进行的 Hook 类型
*
- * [ZYGOTE] 为 [IXposedHookZygoteInit.initZygote]
- *
- * [PACKAGE] 为 [IXposedHookLoadPackage.handleLoadPackage]
- *
- * [RESOURCES] 为 [IXposedHookInitPackageResources.handleInitPackageResources]
+ * - ❗装载代码将自动生成 - 请勿手动调用
*/
-@YukiPrivateApi
+@YukiGenerateApi
enum class HookEntryType {
- /** initZygote */
+ /** 装载 Zygote */
ZYGOTE,
- /** handleLoadPackage */
+ /** 装载 APP */
PACKAGE,
- /** handleInitPackageResources */
+ /** 装载 Resources Hook */
RESOURCES
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.kt
index b50b3b7c..7a3204a4 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.kt
@@ -25,7 +25,7 @@
*
* This file is Created by fankes on 2022/5/16.
*/
-@file:Suppress("StaticFieldLeak", "UNCHECKED_CAST", "unused", "MemberVisibilityCanBePrivate", "DEPRECATION", "KotlinConstantConditions")
+@file:Suppress("unused", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST", "StaticFieldLeak", "KotlinConstantConditions")
package com.highcapable.yukihookapi.hook.xposed.channel
@@ -48,11 +48,11 @@ import com.highcapable.yukihookapi.hook.log.YukiLoggerData
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
import com.highcapable.yukihookapi.hook.xposed.channel.data.wrapper.ChannelDataWrapper
import com.highcapable.yukihookapi.hook.xposed.channel.priority.ChannelPriority
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import java.io.Serializable
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.round
@@ -75,7 +75,10 @@ class YukiHookDataChannel private constructor() {
internal companion object {
/** 是否为 (Xposed) 宿主环境 */
- private val isXposedEnvironment = YukiHookBridge.hasXposedBridge
+ private val isXposedEnvironment = YukiXposedModule.isXposedEnvironment
+
+ /** 自动生成的 Xposed 模块构建版本号 */
+ private val moduleGeneratedVersion = YukiHookAPI.Status.compiledTimestamp.toString()
/**
* 系统广播允许发送的最大数据字节大小
@@ -154,7 +157,7 @@ class YukiHookDataChannel private constructor() {
/** 检查 API 装载状态 */
private fun checkApi() {
if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookDataChannel not allowed in Custom Hook API")
- if (YukiHookBridge.hasXposedBridge && YukiHookBridge.modulePackageName.isBlank())
+ if (isXposedEnvironment && YukiXposedModule.modulePackageName.isBlank())
error("Xposed modulePackageName load failed, please reset and rebuild it")
isAllowSendTooLargeData = false
}
@@ -165,6 +168,7 @@ class YukiHookDataChannel private constructor() {
* @return [Boolean]
*/
private fun isCurrentBroadcast(context: Context?) = runCatching {
+ @Suppress("DEPRECATION")
context is Application || isXposedEnvironment || (((context ?: receiverContext)
?.getSystemService(ACTIVITY_SERVICE) as? ActivityManager?)
?.getRunningTasks(9999)?.filter { context?.javaClass?.name == it?.topActivity?.className }?.size ?: 0) > 0
@@ -183,7 +187,7 @@ class YukiHookDataChannel private constructor() {
* @return [String]
*/
private fun moduleActionName(context: Context? = null) = "yukihookapi.intent.action.MODULE_DATA_CHANNEL_${
- YukiHookBridge.modulePackageName.ifBlank { context?.packageName ?: "" }.trim().hashCode()
+ YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "" }.trim().hashCode()
}"
/**
@@ -204,7 +208,7 @@ class YukiHookDataChannel private constructor() {
nameSpace(context, packageName, isSecure = false).with {
/** 注册监听模块与宿主的版本是否匹配 */
wait(GET_MODULE_GENERATED_VERSION) { fromPackageName ->
- nameSpace(context, fromPackageName, isSecure = false).put(RESULT_MODULE_GENERATED_VERSION, YukiHookBridge.moduleGeneratedVersion)
+ nameSpace(context, fromPackageName, isSecure = false).put(RESULT_MODULE_GENERATED_VERSION, moduleGeneratedVersion)
}
/** 注册监听模块与宿主之间的调试日志数据 */
wait(GET_YUKI_LOGGER_INMEMORY_DATA) { fromPackageName ->
@@ -368,7 +372,7 @@ class YukiHookDataChannel private constructor() {
* @param result 回调是否匹配
*/
fun checkingVersionEquals(priority: ChannelPriority? = null, result: (Boolean) -> Unit) {
- wait(RESULT_MODULE_GENERATED_VERSION, priority) { result(it == YukiHookBridge.moduleGeneratedVersion) }
+ wait(RESULT_MODULE_GENERATED_VERSION, priority) { result(it == moduleGeneratedVersion) }
put(GET_MODULE_GENERATED_VERSION, packageName)
}
@@ -651,11 +655,11 @@ class YukiHookDataChannel private constructor() {
if (isSecure && context != null) if (isXposedEnvironment.not() && context !is Activity)
error("YukiHookDataChannel only support used on an Activity, but this current context is \"${context.javaClass.name}\"")
/** 发送广播 */
- (context ?: YukiHookAppHelper.currentApplication())?.sendBroadcast(Intent().apply {
+ (context ?: AppParasitics.currentApplication)?.sendBroadcast(Intent().apply {
action = if (isXposedEnvironment) moduleActionName() else hostActionName(packageName)
/** 由于系统框架的包名可能不唯一 - 为防止发生问题不再对系统框架的广播设置接收者包名 */
- if (packageName != YukiHookBridge.SYSTEM_FRAMEWORK_NAME)
- setPackage(if (isXposedEnvironment) YukiHookBridge.modulePackageName else packageName)
+ if (packageName != AppParasitics.SYSTEM_FRAMEWORK_NAME)
+ setPackage(if (isXposedEnvironment) YukiXposedModule.modulePackageName else packageName)
putExtra(wrapper.instance.key + keyNonRepeatName, wrapper)
}) ?: yLoggerE(msg = "Failed to sendBroadcast like \"${wrapper.instance.key}\", because got null context in \"$packageName\"")
}
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
index 50268393..b6072f09 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt
@@ -30,11 +30,9 @@
package com.highcapable.yukihookapi.hook.xposed.parasitic
-import android.app.Activity
-import android.app.ActivityManager
-import android.app.Application
-import android.app.Instrumentation
+import android.app.*
import android.content.*
+import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
@@ -42,21 +40,20 @@ import android.os.Build
import android.os.Handler
import androidx.annotation.RequiresApi
import com.highcapable.yukihookapi.YukiHookAPI
+import com.highcapable.yukihookapi.hook.core.api.compat.HookApiProperty
+import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberHook
+import com.highcapable.yukihookapi.hook.core.api.proxy.YukiMemberReplacement
import com.highcapable.yukihookapi.hook.factory.*
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
-import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.type.android.*
import com.highcapable.yukihookapi.hook.type.java.*
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookCallback
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook
-import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberReplacement
-import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
+import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleStatus
+import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.config.ActivityProxyConfig
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.HandlerDelegate
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.IActivityManagerProxy
@@ -69,6 +66,9 @@ import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.Instr
*/
internal object AppParasitics {
+ /** Android 系统框架名称 */
+ internal const val SYSTEM_FRAMEWORK_NAME = "android"
+
/** [YukiHookDataChannel] 是否已经注册 */
private var isDataChannelRegistered = false
@@ -88,12 +88,6 @@ internal object AppParasitics {
*/
internal var hostApplication: Application? = null
- /** 当前 Xposed 模块自身 APK 路径 */
- internal var moduleAppFilePath = ""
-
- /** 当前 Xposed 模块自身 [Resources] */
- internal var moduleAppResources: YukiModuleResources? = null
-
/**
* 当前环境中使用的 [ClassLoader]
*
@@ -103,12 +97,6 @@ internal object AppParasitics {
*/
internal val baseClassLoader get() = classOf().classLoader ?: error("Operating system not supported")
- /**
- * 获取当前 Xposed 模块自身动态 [Resources]
- * @return [YukiModuleResources] or null
- */
- internal val dynamicModuleAppResources get() = runCatching { YukiModuleResources.wrapper(moduleAppFilePath) }.getOrNull()
-
/**
* 获取当前系统框架的 [Context]
* @return [Context] ContextImpl 实例对象
@@ -119,6 +107,43 @@ internal object AppParasitics {
ActivityThreadClass.method { name = "getSystemContext" }.ignored().get(it).invoke()
} ?: error("Failed to got SystemContext")
+ /**
+ * 获取当前宿主的 [Application]
+ * @return [Application] or null
+ */
+ internal val currentApplication
+ get() = runCatching { AndroidAppHelper.currentApplication() }.getOrNull() ?: runCatching {
+ ActivityThreadClass.method { name = "currentApplication" }.ignored().get().invoke()
+ }.getOrNull()
+
+ /**
+ * 获取当前宿主的 [ApplicationInfo]
+ * @return [ApplicationInfo] or null
+ */
+ internal val currentApplicationInfo
+ get() = runCatching { AndroidAppHelper.currentApplicationInfo() }.getOrNull() ?: runCatching {
+ ActivityThreadClass.method { name = "currentActivityThread" }.ignored().get().call()
+ ?.current(ignored = true)?.field { name = "mBoundApplication" }
+ ?.current(ignored = true)?.field { name = "appInfo" }
+ ?.cast()
+ }.getOrNull()
+
+ /**
+ * 获取当前宿主的包名
+ * @return [String]
+ */
+ internal val currentPackageName get() = currentApplicationInfo?.packageName ?: SYSTEM_FRAMEWORK_NAME
+
+ /**
+ * 获取当前宿主的进程名
+ * @return [String]
+ */
+ internal val currentProcessName
+ get() = runCatching { AndroidAppHelper.currentProcessName() }.getOrNull() ?: runCatching {
+ ActivityThreadClass.method { name = "currentPackageName" }.ignored().get().string()
+ .takeIf { it.isNotBlank() } ?: SYSTEM_FRAMEWORK_NAME
+ }.getOrNull() ?: SYSTEM_FRAMEWORK_NAME
+
/**
* 获取指定 [packageName] 的用户 ID
*
@@ -133,10 +158,30 @@ internal object AppParasitics {
}.ignored().get().int(systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid)
}.getOrNull() ?: 0
+ /**
+ * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
+ * @param loader 当前 [ClassLoader]
+ * @param result 回调 - ([Class] 实例对象)
+ */
+ internal fun hookClassLoader(loader: ClassLoader?, result: (Class<*>) -> Unit) {
+ if (loader == null) return
+ if (YukiXposedModule.isXposedEnvironment.not()) return yLoggerW(msg = "You can only use hook ClassLoader method in Xposed Environment")
+ classLoaderCallbacks[loader.hashCode()] = result
+ if (isClassLoaderHooked) return
+ runCatching {
+ YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringClass, BooleanType) }, object : YukiMemberHook() {
+ override fun afterHookedMember(param: Param) {
+ param.instance?.also { loader ->
+ (param.result as? Class<*>?)?.also { classLoaderCallbacks[loader.hashCode()]?.invoke(it) }
+ }
+ }
+ })
+ isClassLoaderHooked = true
+ }.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") }
+ }
+
/**
* Hook 模块 APP 相关功能 - 包括自身激活状态、Resources Hook 支持状态以及 [SharedPreferences]
- *
- * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
* @param loader 模块的 [ClassLoader]
* @param type 当前正在进行的 Hook 类型
*/
@@ -147,18 +192,33 @@ internal object AppParasitics {
if ((param.args?.get(0) as? String?)?.endsWith("preferences.xml") == true) param.args?.set(1, 1)
}
})
- if (YukiHookAPI.Configs.isEnableHookModuleStatus) YukiHookModuleStatus.IMPL_CLASS_NAME.toClassOrNull(loader)?.apply {
+ if (YukiHookAPI.Configs.isEnableHookModuleStatus.not()) return
+ YukiXposedModuleStatus.IMPL_CLASS_NAME.toClassOrNull(loader)?.apply {
if (type != HookEntryType.RESOURCES) {
- YukiHookHelper.hook(method { name = YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME }, object : YukiMemberReplacement() {
- override fun replaceHookedMember(param: Param) = true
- })
- YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME }, object : YukiMemberReplacement() {
- override fun replaceHookedMember(param: Param) = YukiHookBridge.executorName
- })
- YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME }, object : YukiMemberReplacement() {
- override fun replaceHookedMember(param: Param) = YukiHookBridge.executorVersion
- })
- } else YukiHookHelper.hook(method { name = YukiHookModuleStatus.IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME },
+ YukiHookHelper.hook(method { name = YukiXposedModuleStatus.IS_ACTIVE_METHOD_NAME },
+ object : YukiMemberReplacement() {
+ override fun replaceHookedMember(param: Param) = true
+ })
+ YukiHookHelper.hook(method { name = YukiXposedModuleStatus.GET_EXECUTOR_NAME_METHOD_NAME },
+ object : YukiMemberReplacement() {
+ override fun replaceHookedMember(param: Param) = HookApiProperty.name
+ })
+ YukiHookHelper.hook(
+ method { name = YukiXposedModuleStatus.GET_EXECUTOR_API_LEVEL_METHOD_NAME },
+ object : YukiMemberReplacement() {
+ override fun replaceHookedMember(param: Param) = HookApiProperty.apiLevel
+ })
+ YukiHookHelper.hook(
+ method { name = YukiXposedModuleStatus.GET_EXECUTOR_VERSION_NAME_METHOD_NAME },
+ object : YukiMemberReplacement() {
+ override fun replaceHookedMember(param: Param) = HookApiProperty.versionName
+ })
+ YukiHookHelper.hook(
+ method { name = YukiXposedModuleStatus.GET_EXECUTOR_VERSION_CODE_METHOD_NAME },
+ object : YukiMemberReplacement() {
+ override fun replaceHookedMember(param: Param) = HookApiProperty.versionCode
+ })
+ } else YukiHookHelper.hook(method { name = YukiXposedModuleStatus.IS_SUPPORT_RESOURCES_HOOK_METHOD_NAME },
object : YukiMemberReplacement() {
override fun replaceHookedMember(param: Param) = true
})
@@ -245,8 +305,7 @@ internal object AppParasitics {
runCatching {
/** 过滤系统框架与一系列服务组件包名不唯一的情况 */
if (isDataChannelRegistered ||
- (YukiHookAppHelper.currentPackageName() == YukiHookBridge.SYSTEM_FRAMEWORK_NAME &&
- packageName != YukiHookBridge.SYSTEM_FRAMEWORK_NAME)
+ (currentPackageName == SYSTEM_FRAMEWORK_NAME && packageName != SYSTEM_FRAMEWORK_NAME)
) return
YukiHookDataChannel.instance().register(it, packageName)
isDataChannelRegistered = true
@@ -258,47 +317,23 @@ internal object AppParasitics {
}
}
- /**
- * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
- * @param loader 当前 [ClassLoader]
- * @param result 回调 - ([Class] 实例对象)
- */
- internal fun hookClassLoader(loader: ClassLoader?, result: (Class<*>) -> Unit) {
- if (loader == null) return
- if (YukiHookBridge.hasXposedBridge.not()) return yLoggerW(msg = "You can only use hook ClassLoader method in Xposed Environment")
- classLoaderCallbacks[loader.hashCode()] = result
- if (isClassLoaderHooked) return
- runCatching {
- YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringClass, BooleanType) }, object : YukiMemberHook() {
- override fun afterHookedMember(param: Param) {
- param.instance?.also { loader ->
- (param.result as? Class<*>?)?.also { classLoaderCallbacks[loader.hashCode()]?.invoke(it) }
- }
- }
- })
- isClassLoaderHooked = true
- }.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") }
- }
-
/**
* 向 Hook APP (宿主) 注入当前 Xposed 模块的资源
* @param hostResources 需要注入的宿主 [Resources]
*/
internal fun injectModuleAppResources(hostResources: Resources) {
- if (YukiHookBridge.hasXposedBridge) runCatching {
- if (YukiHookAppHelper.currentPackageName() == YukiHookBridge.modulePackageName)
+ if (YukiXposedModule.isXposedEnvironment) runCatching {
+ if (currentPackageName == YukiXposedModule.modulePackageName)
return yLoggerE(msg = "You cannot inject module resources into yourself")
- hostResources.assets.current(ignored = true).method { name = "addAssetPath"; param(StringClass) }.call(moduleAppFilePath)
+ hostResources.assets.current(ignored = true).method {
+ name = "addAssetPath"
+ param(StringClass)
+ }.call(YukiXposedModule.moduleAppFilePath)
}.onFailure {
yLoggerE(msg = "Failed to inject module resources into [$hostResources]", e = it)
} else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
}
- /** 刷新当前 Xposed 模块自身 [Resources] */
- internal fun refreshModuleAppResources() {
- dynamicModuleAppResources?.let { moduleAppResources = it }
- }
-
/**
* 向 Hook APP (宿主) 注册当前 Xposed 模块的 [Activity]
* @param context 当前 [Context]
@@ -307,12 +342,12 @@ internal object AppParasitics {
@RequiresApi(Build.VERSION_CODES.N)
internal fun registerModuleAppActivities(context: Context, proxy: Any?) {
if (isActivityProxyRegistered) return
- if (YukiHookBridge.hasXposedBridge.not()) return yLoggerW(msg = "You can only register Activity Proxy in Xposed Environment")
- if (context.packageName == YukiHookBridge.modulePackageName) return yLoggerE(msg = "You cannot register Activity Proxy into yourself")
+ if (YukiXposedModule.isXposedEnvironment.not()) return yLoggerW(msg = "You can only register Activity Proxy in Xposed Environment")
+ if (context.packageName == YukiXposedModule.modulePackageName) return yLoggerE(msg = "You cannot register Activity Proxy into yourself")
if (Build.VERSION.SDK_INT < 24) return yLoggerE(msg = "Activity Proxy only support for Android 7.0 (API 24) or higher")
runCatching {
ActivityProxyConfig.apply {
- proxyIntentName = "${YukiHookBridge.modulePackageName}.ACTIVITY_PROXY_INTENT"
+ proxyIntentName = "${YukiXposedModule.modulePackageName}.ACTIVITY_PROXY_INTENT"
proxyClassName = proxy?.let {
when (it) {
is String, is CharSequence -> it.toString()
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.kt
index 0e644ab6..8b4236cc 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.kt
@@ -35,7 +35,7 @@ import android.os.Bundle
import androidx.annotation.CallSuper
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.reference.ModuleClassLoader
/**
@@ -51,7 +51,7 @@ open class ModuleAppActivity : Activity() {
@CallSuper
override fun onConfigurationChanged(newConfig: Configuration) {
- if (YukiHookBridge.hasXposedBridge) injectModuleAppResources()
+ if (YukiXposedModule.isXposedEnvironment) injectModuleAppResources()
super.onConfigurationChanged(newConfig)
}
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.kt
index 9cb7d396..5a918533 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.kt
@@ -36,7 +36,7 @@ import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.registerModuleAppActivities
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.reference.ModuleClassLoader
/**
@@ -60,7 +60,7 @@ open class ModuleAppCompatActivity : AppCompatActivity() {
@CallSuper
override fun onConfigurationChanged(newConfig: Configuration) {
- if (YukiHookBridge.hasXposedBridge) injectModuleAppResources()
+ if (YukiXposedModule.isXposedEnvironment) injectModuleAppResources()
super.onConfigurationChanged(newConfig)
}
@@ -72,7 +72,7 @@ open class ModuleAppCompatActivity : AppCompatActivity() {
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
- if (YukiHookBridge.hasXposedBridge && moduleTheme != -1) setTheme(moduleTheme)
+ if (YukiXposedModule.isXposedEnvironment && moduleTheme != -1) setTheme(moduleTheme)
super.onCreate(savedInstanceState)
}
}
\ No newline at end of file
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/HandlerDelegate.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/HandlerDelegate.kt
index ad12efdb..afb73e0b 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/HandlerDelegate.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/HandlerDelegate.kt
@@ -42,7 +42,7 @@ import com.highcapable.yukihookapi.hook.type.android.ActivityThreadClass
import com.highcapable.yukihookapi.hook.type.android.ClientTransactionClass
import com.highcapable.yukihookapi.hook.type.android.IBinderClass
import com.highcapable.yukihookapi.hook.type.android.IntentClass
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
+import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.config.ActivityProxyConfig
/**
@@ -73,7 +73,7 @@ internal class HandlerDelegate private constructor(private val baseInstance: Han
msg.obj.current(ignored = true).field { name = "intent" }.apply {
cast()?.also { intent ->
IntentClass.field { name = "mExtras" }.ignored().get(intent).cast()
- ?.classLoader = YukiHookAppHelper.currentApplication()?.classLoader
+ ?.classLoader = AppParasitics.currentApplication?.classLoader
if (intent.hasExtra(ActivityProxyConfig.proxyIntentName))
set(intent.getParcelableExtra(ActivityProxyConfig.proxyIntentName))
}
@@ -86,7 +86,7 @@ internal class HandlerDelegate private constructor(private val baseInstance: Han
?.apply {
cast()?.also { intent ->
IntentClass.field { name = "mExtras" }.ignored().get(intent).cast()
- ?.classLoader = YukiHookAppHelper.currentApplication()?.classLoader
+ ?.classLoader = AppParasitics.currentApplication?.classLoader
if (intent.hasExtra(ActivityProxyConfig.proxyIntentName))
intent.getParcelableExtra(ActivityProxyConfig.proxyIntentName).also { subIntent ->
if (Build.VERSION.SDK_INT >= 31)
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/IActivityManagerProxy.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/IActivityManagerProxy.kt
index b46bc7c7..d4d98dee 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/IActivityManagerProxy.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/IActivityManagerProxy.kt
@@ -30,8 +30,7 @@ package com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate
import android.app.ActivityManager
import android.content.Intent
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.config.ActivityProxyConfig
import java.lang.reflect.InvocationHandler
@@ -61,8 +60,8 @@ internal class IActivityManagerProxy private constructor(private val baseInstanc
val argsInstance = (args[index] as? Intent) ?: return@also
val component = argsInstance.component
if (component != null &&
- component.packageName == YukiHookAppHelper.currentPackageName() &&
- component.className.startsWith(YukiHookBridge.modulePackageName)
+ component.packageName == AppParasitics.currentPackageName &&
+ component.className.startsWith(YukiXposedModule.modulePackageName)
) args[index] = Intent().apply {
setClassName(component.packageName, ActivityProxyConfig.proxyClassName)
putExtra(ActivityProxyConfig.proxyIntentName, argsInstance)
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/InstrumentationDelegate.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/InstrumentationDelegate.kt
index 43e8fe5e..3464fbda 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/InstrumentationDelegate.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/delegate/InstrumentationDelegate.kt
@@ -41,7 +41,7 @@ import android.os.*
import android.view.KeyEvent
import android.view.MotionEvent
import com.highcapable.yukihookapi.hook.factory.*
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
/**
@@ -65,15 +65,15 @@ internal class InstrumentationDelegate private constructor(private val baseInsta
* @param icicle [Bundle]
*/
private fun Activity.injectLifecycle(icicle: Bundle?) {
- if (icicle != null && current().name.startsWith(YukiHookBridge.modulePackageName))
+ if (icicle != null && current().name.startsWith(YukiXposedModule.modulePackageName))
icicle.classLoader = AppParasitics.baseClassLoader
- if (current().name.startsWith(YukiHookBridge.modulePackageName)) injectModuleAppResources()
+ if (current().name.startsWith(YukiXposedModule.modulePackageName)) injectModuleAppResources()
}
override fun newActivity(cl: ClassLoader?, className: String?, intent: Intent?): Activity? = try {
baseInstance.newActivity(cl, className, intent)
} catch (e: Throwable) {
- if (className?.startsWith(YukiHookBridge.modulePackageName) == true)
+ if (className?.startsWith(YukiXposedModule.modulePackageName) == true)
className.toClass().buildOf() ?: throw e
else throw e
}
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.kt
index 0df8078d..a53b345c 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.kt
@@ -35,7 +35,7 @@ import android.content.res.Configuration
import android.content.res.Resources
import android.view.ContextThemeWrapper
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.reference.ModuleClassLoader
/**
@@ -73,7 +73,7 @@ class ModuleContextThemeWrapper private constructor(baseContext: Context, theme:
baseResources = baseContext.createConfigurationContext(it)?.resources
baseResources?.updateConfiguration(it, baseContext.resources.displayMetrics)
}
- if (YukiHookBridge.hasXposedBridge) resources?.injectModuleAppResources()
+ if (YukiXposedModule.isXposedEnvironment) resources?.injectModuleAppResources()
}
/**
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.kt
index ab6eb250..9cc127e4 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.kt
@@ -30,8 +30,7 @@
package com.highcapable.yukihookapi.hook.xposed.parasitic.reference
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
-import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
/**
@@ -89,8 +88,8 @@ class ModuleClassLoader private constructor() : ClassLoader(AppParasitics.baseCl
private val baseLoader get() = AppParasitics.baseClassLoader
override fun loadClass(name: String, resolve: Boolean): Class<*> {
- if (YukiHookBridge.hasXposedBridge.not()) return baseLoader.loadClass(name)
- return YukiHookAppHelper.currentApplication()?.classLoader?.let { hostLoader ->
+ if (YukiXposedModule.isXposedEnvironment.not()) return baseLoader.loadClass(name)
+ return AppParasitics.currentApplication?.classLoader?.let { hostLoader ->
excludeHostClasses.takeIf { it.isNotEmpty() }?.forEach { runCatching { if (name == it) return@let hostLoader.loadClass(name) } }
excludeModuleClasses.takeIf { it.isNotEmpty() }?.forEach { runCatching { if (name == it) return@let baseLoader.loadClass(name) } }
runCatching { return@let baseLoader.loadClass(name) }
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 b37e7111..dd84b6ca 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
@@ -25,10 +25,7 @@
*
* This file is Created by fankes on 2022/2/8.
*/
-@file:Suppress(
- "SetWorldReadable", "CommitPrefEdits", "DEPRECATION", "WorldReadableFiles",
- "unused", "UNCHECKED_CAST", "MemberVisibilityCanBePrivate", "StaticFieldLeak"
-)
+@file:Suppress("unused", "MemberVisibilityCanBePrivate", "StaticFieldLeak", "SetWorldReadable", "CommitPrefEdits", "UNCHECKED_CAST")
package com.highcapable.yukihookapi.hook.xposed.prefs
@@ -38,7 +35,7 @@ import androidx.preference.PreferenceFragmentCompat
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
-import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
+import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment
import de.robv.android.xposed.XSharedPreferences
@@ -70,8 +67,8 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
internal companion object {
- /** 是否为 (Xposed) 宿主环境 */
- private val isXposedEnvironment = YukiHookBridge.hasXposedBridge
+ /** 当前是否为 (Xposed) 宿主环境 */
+ private val isXposedEnvironment = YukiXposedModule.isXposedEnvironment
/** 当前 [YukiHookModulePrefs] 单例 */
private var instance: YukiHookModulePrefs? = null
@@ -102,7 +99,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
}
/** 存储名称 - 默认包名 + _preferences */
- private var prefsName = "${YukiHookBridge.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
+ private var prefsName = "${YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
/** 是否使用键值缓存 */
private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache
@@ -147,7 +144,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
/** 检查 API 装载状态 */
private fun checkApi() {
if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookModulePrefs not allowed in Custom Hook API")
- if (isXposedEnvironment && YukiHookBridge.modulePackageName.isBlank())
+ if (isXposedEnvironment && YukiXposedModule.modulePackageName.isBlank())
error("Xposed modulePackageName load failed, please reset and rebuild it")
}
@@ -158,7 +155,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
private val xPrefs
get() = checkApi().let {
runCatching {
- XSharedPreferences(YukiHookBridge.modulePackageName, prefsName).apply {
+ XSharedPreferences(YukiXposedModule.modulePackageName, prefsName).apply {
checkApi()
makeWorldReadable()
reload()
@@ -174,6 +171,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
private val sPrefs
get() = checkApi().let {
runCatching {
+ @Suppress("DEPRECATION", "WorldReadableFiles")
context?.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE).also { isUsingNewXSharedPreferences = true }
?: error("YukiHookModulePrefs missing Context instance")
}.getOrElse {
diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt
index 28b76ce8..263b5c2d 100644
--- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt
+++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt
@@ -25,8 +25,6 @@
*
* This file is Created by fankes on 2022/4/17.
*/
-@file:Suppress("WorldReadableFiles", "DEPRECATION")
-
package com.highcapable.yukihookapi.hook.xposed.prefs.ui
import android.app.Activity
@@ -105,6 +103,7 @@ abstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPref
/** 设置自动适配模块 Sp 存储全局可读可写 */
private fun makeNewXShareReadableIfPossible() = runCatching {
+ @Suppress("DEPRECATION", "WorldReadableFiles")
currentActivity.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)
}.onFailure { YukiHookModulePrefs.makeWorldReadable(currentActivity, prefsFileName = "$prefsName.xml") }.unit()
}
\ No newline at end of file