From 9b4d11313d7097f14a0cf851fa051c176cce0ec6 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Fri, 15 Apr 2022 14:56:51 +0800 Subject: [PATCH] Merge document file --- README.md | 4 +- docs/_coverpage.md | 2 +- docs/_navbar.md | 1 + docs/_sidebar.md | 1 + docs/config/api-exception.md | 25 +++- docs/config/r8-proguard.md | 8 +- docs/guide/move-to-new-api.md | 221 ++++++++++++++++++++++++++++++++++ docs/guide/quick-start.md | 2 + 8 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 docs/guide/move-to-new-api.md diff --git a/README.md b/README.md index 3cc1533d..35735c96 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ - [点击这里](https://fankes.github.io/YukiHookAPI) 前往文档页面查看更多详细教程和内容。 -> 你或许可能会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新,以获取最新版本或清除浏览器缓存。 +> 你大概率会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新一次以同步最新版本,或清除浏览器缓存。 -最新版本更新时间:2022-04-15 04:57 +最新版本更新时间:2022-04-15 14:56 ## Contacts diff --git a/docs/_coverpage.md b/docs/_coverpage.md index ceb03768..0cdc9919 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -12,7 +12,7 @@ - 方便移植 快速上手 -`更新时间 2022-04-15 04:57` +`更新时间 2022-04-15 14:56` [GitHub](https://github.com/fankes/YukiHookAPI) [Get Started](#介绍) diff --git a/docs/_navbar.md b/docs/_navbar.md index 9127d7c8..8b61fa1f 100644 --- a/docs/_navbar.md +++ b/docs/_navbar.md @@ -4,6 +4,7 @@ * [快速开始](guide/quick-start) * [用法示例](guide/example) * [特色功能](guide/special-feature) + * [从 Xposed API 迁移](guide/move-to-new-api) * 配置 * [API 基本配置](config/api-example) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 13fdeafa..4d089def 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -4,6 +4,7 @@ * [快速开始](guide/quick-start) * [用法示例](guide/example) * [特色功能](guide/special-feature) + * [从 Xposed API 迁移](guide/move-to-new-api) * 配置 * [API 基本配置](config/api-example) diff --git a/docs/config/api-exception.md b/docs/config/api-exception.md index de673020..d716f46d 100644 --- a/docs/config/api-exception.md +++ b/docs/config/api-exception.md @@ -359,17 +359,38 @@ method { 异常原因 -使用 `ModuleApplication` 时调用了 `appContext` 功能但是 APP 可能已经被销毁或没有正确启动。 +> 第一种情况 + +在被 Hook 的宿主内调用了 `ModuleApplication` 的 `appContext`。 + +> 示例如下 + +```kotlin +encase { + // 调用了此变量 + ModuleApplication.appContext... +} +``` + +> 第二种情况 + +使用 `ModuleApplication` 时调用了 `appContext` 但是 APP 可能已经被销毁或没有正确启动。 > 示例如下 ```kotlin // 调用了此变量但是 APP 可能已被销毁或没有正确启动 -ModuleApplication.appContext +ModuleApplication.appContext... ``` 解决方案 +> 第一种情况 + +你只能在模块内使用 `ModuleApplication` 的 `appContext`,在宿主内请使用 `PackageParam` 中的 `appContext`,请确认你使用的是否正确。 + +> 第二种情况 + 这种情况基本不存在,由于 `appContext` 是在 `onCreate` 中被赋值的,除非遇到多进程并发启动或 APP 没有启动完成前被反射调用了父类的 `onCreate` 方法。 !> `IllegalStateException` YukiHookModulePrefs not allowed in Custom Hook API diff --git a/docs/config/r8-proguard.md b/docs/config/r8-proguard.md index 561f6dfc..d0753c38 100644 --- a/docs/config/r8-proguard.md +++ b/docs/config/r8-proguard.md @@ -8,18 +8,18 @@ ## Proguard -> 如果你仍然在使用 `Proguard`,你需要做一些规则配置。 +> ~~如果你仍然在使用 `Proguard`,你需要做一些规则配置。~~ -在 `proguard-rules.pro` 添加如下代码即可。 +~~在 `proguard-rules.pro` 添加如下代码即可。~~ -> 示例如下 +> ~~示例如下~~ ```proguard -keep class com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus {*;} -keep class 这里填你的 HookEntryClass 入口类完整包名_YukiHookXposedInit {*;} ``` -!> 自从 Android Gradle Plugin 4.2 后,拥有 Android Jetpack 套件最新版本的混淆处理程序默认均为 `R8`,基本可以不需要考虑混淆的问题。 +!> Proguard 规则已被弃用,请不要再使用,自从 Android Gradle Plugin 4.2 后,拥有 Android Jetpack 套件最新版本的混淆处理程序默认均为 `R8`,基本可以不需要考虑混淆的问题。 若要在任何版本下启用 `R8`,请在 `gradle.properties` 文件中加入如下规则,Android Gradle Plugin 7.0 及以上版本无需任何配置。 diff --git a/docs/guide/move-to-new-api.md b/docs/guide/move-to-new-api.md new file mode 100644 index 00000000..775c3742 --- /dev/null +++ b/docs/guide/move-to-new-api.md @@ -0,0 +1,221 @@ +# 从 Xposed API 迁移 + +> 若你熟悉 Xposed API,你可以参考下方的相同点将自己的 API 快速迁移到 `YukiHookAPI`。 + +## 迁移 Hook 入口点 + +> 从 `XC_LoadPackage.LoadPackageParam` 迁移至 `PackageParam`。 + +`YukiHookAPI` 对 `PackageParam` 实现了 `lambda` 方法体 `this` 用法,在 `encase` 方法体内即可全局得到 `PackageParam` 对象。 + +> API 功能差异对比如下 + + + +#### **Yuki Hook API** + +```kotlin +override fun onHook() = encase { + // 得到当前 Hook 的包名 + packageName + // 得到当前 Hook 的 ApplicationInfo + appInfo + // 得到宿主 Application 生命周期 + appContext + // 创建 Hook + findClass("com.demo.Test").hook { + injectMember { + method { + name = "test" + param(BooleanType) + } + afterHook { + // ... + } + } + } +} +``` + +#### **Xposed API** + +```kotlin +override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + // 得到当前 Hook 的包名 + lpparam.packageName + // 得到当前 Hook 的 ApplicationInfo + lpparam.applicationInfo + // 得到宿主 Application 生命周期 + AndroidAppHelper.currentApplication() + // 创建 Hook + XposedHelpers.findAndHookMethod("com.demo.Test", lpparam.classLoader, "test", Boolean::class.java, object : XC_MethodHook() { + override fun afterHookedMethod(param: MethodHookParam) { + // ... + } + }) +} +``` + + + +## 迁移 Hook 方法体 + +> 从 `XC_MethodHook.MethodHookParam` 迁移至 `HookParam`。 + +### Before/After Hook + +`YukiHookAPI` 同样对 `HookParam` 实现了 `lambda` 方法体 `this` 用法,在 `beforeHook`、`afterHook` 等方法体内即可全局得到 `HookParam` 对象。 + +> API 功能差异对比如下 + + + +#### **Yuki Hook API** + +```kotlin +afterHook { + // 得到当前 Hook 的实例 + instance + // 得到当前 Hook 的 Class 实例 + instanceClass + // 得到并 cast 当前 Hook 的实例为指定类型 T + instance() + // 得到方法参数数组 + args + // 得到方法参数的第一位 T + args().first().cast() + // 得到方法参数的最后一位 T + args().last().cast() + // 得到方法参数的任意下标 T,这里用 2 举例 + args(index = 2).cast() + // 设置方法参数的任意下标,这里用 2 举例 + args(index = 2).set(...) + // 得到返回值 + result + // 得到返回值并 cast 为 T + result() + // 修改返回值内容 + result = ... + // 删除返回值内容 + resultNull() + // 执行未经 Hook 的原始方法 + method.invokeOriginal(...) +} +``` + +#### **Xposed API** + +```kotlin +override fun afterHookedMethod(param: MethodHookParam) { + // 得到当前 Hook 的实例 + param.thisObject + // 得到当前 Hook 的 Class 实例 + param.thisObject.javaClass + // 得到并 cast 当前 Hook 的实例为指定类型 T + param.thisObject as T + // 得到方法参数数组 + param.args + // 得到方法参数的第一位 T + param.args[0] as T + // 得到方法参数的最后一位 T + param.args[param.args.lastIndex] as T + // 得到方法参数的任意下标 T,这里用 2 举例 + param.args[2] as T + // 设置方法参数的任意下标,这里用 2 举例 + param.args[2] = ... + // 得到返回值 + param.result + // 得到返回值并 cast 为 T + param.result as T + // 修改返回值内容 + param.result = ... + // 删除返回值内容 + param.result = null + // 执行未经 Hook 的原始方法 + XposedBridge.invokeOriginalMethod(param.method, param.thisObject, ...) +} +``` + + + +### Replace Hook + +`replaceHook` 方法比较特殊,`YukiHookAPI` 为它做出了多种形式以供选择。 + +> API 功能差异对比如下 + + + +#### **Yuki Hook API** + +无返回值的方法 `void`。 + +```kotlin +replaceUnit { + // 直接在这里实现被替换的逻辑 +} +``` + +有返回值的方法。 + +```kotlin +replaceAny { + // 在这里实现被替换的逻辑 + // ... + // 需要返回方法对应的返回值,无需写 return,只需将参数放到最后一位 + // 假设这个方法的返回值是 Int,我们只需要保证最后一位是我们需要的返回值即可 + 0 +} +``` + +有些方法我们只需替换其返回值,则有如下实现。 + +```kotlin +// 替换为你需要的返回值 +replaceTo(...) +// 替换为 Boolean 类型的返回值 +replaceToTrue() +// 拦截返回值 +intercept() +``` + +!> 直接替换返回值的方法传入的参数是固定不变的,若想实现动态替换返回值请使用 `replaceAny` 方法体。 + +#### **Xposed API** + +无返回值的方法 `void`。 + +```kotlin +override fun replaceHookedMethod(param: MethodHookParam): Any? { + // 直接在这里实现被替换的逻辑 + return null +} +``` + +有返回值的方法。 + +```kotlin +override fun replaceHookedMethod(param: MethodHookParam): Int { + // 在这里实现被替换的逻辑 + // ... + // 假设这个方法的返回值是 Int + return 0 +} +``` + +有些方法我们只需替换其返回值,则有如下实现。 + +```kotlin +// 替换为你需要的返回值 +override fun replaceHookedMethod(param: MethodHookParam) = ... +// 替换为 Boolean 类型的返回值 +override fun replaceHookedMethod(param: MethodHookParam) = true +// 拦截返回值 +override fun replaceHookedMethod(param: MethodHookParam) = null +``` + + + +## 迁移其它功能 + +`YukiHookAPI` 对 Xposed API 进行了完全重写,你可以参考 [API 文档](api/home) 以及 [特色功能](guide/special-feature) 来决定一些功能性的迁移和使用。 \ No newline at end of file diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index 9001a241..c9cc754d 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -112,6 +112,8 @@ class MainHook : YukiHookXposedInitProxy { 有关作为 Xposed 模块使用的相关配置详细内容,你可以 [点击这里](config/xposed-using) 继续阅读。 +若你目前正在使用 Xposed API,你可以参考 [从 Xposed API 迁移](guide/move-to-new-api)。 + ## 作为 Hook API 使用 ### 集成方式