Update document file

This commit is contained in:
2022-05-01 09:52:53 +08:00
parent 8d226bc42d
commit dfa3362c35
30 changed files with 1957 additions and 164 deletions

View File

@@ -11,14 +11,6 @@
⛱️ An efficient Kotlin version of the Xposed Hook API. ⛱️ An efficient Kotlin version of the Xposed Hook API.
<br/> <br/>
## Plan is in progress
> `IXposedHookInitPackageResources` and `IXposedHookZygoteInit` are being adapted recently,let's stay tuned
**计划进行中**
> 近期正在适配 `IXposedHookInitPackageResources`、`IXposedHookZygoteInit` 敬请期待
## What's this ## What's this
- This is an efficient Xposed Hook API rebuilt in Kotlin - This is an efficient Xposed Hook API rebuilt in Kotlin
@@ -31,6 +23,18 @@
- 名称取自 [《ももくり》女主 栗原 雪(Yuki)](https://www.bilibili.com/bangumi/play/ss5016) - 名称取自 [《ももくり》女主 栗原 雪(Yuki)](https://www.bilibili.com/bangumi/play/ss5016)
- 前身为 [开发学习项目](https://github.com/fankes/TMore) 中使用的 Innocent Xposed API现在重新命名并开源 - 前身为 [开发学习项目](https://github.com/fankes/TMore) 中使用的 Innocent Xposed API现在重新命名并开源
## Supports
- Standard Hook
- Zygote Hook
- Resources Hook
**支持的功能**
- 标准 Hook
- Zygote Hook
- 资源钩子(Resources Hook)
## Get Started ## Get Started
- [Click here](https://fankes.github.io/YukiHookAPI) go to the documentation page for more detailed tutorials and content. - [Click here](https://fankes.github.io/YukiHookAPI) go to the documentation page for more detailed tutorials and content.

View File

@@ -26,15 +26,7 @@
目前 API 只支持通过自动处理程序绑定到 `xposed_init`,若您不喜欢自动处理程序,一定要自己实现模块装载入口,未来会按照需求人数推出仅有 API 功能的 Lite 版本。 目前 API 只支持通过自动处理程序绑定到 `xposed_init`,若您不喜欢自动处理程序,一定要自己实现模块装载入口,未来会按照需求人数推出仅有 API 功能的 Lite 版本。
### 支持资源 Hook 和注入系统框架 API 已经提供了 Xposed 原生 API 监听接口,你可以 [在这里](config/xposed-using?id=原生-xposed-api-事件) 找到或查看 Demo 的实现方法。
**计划状态:近期**
目前的 API 仅支持 APP 内的功能 Hook并不支持 `Resource` 的替换以及 Hook 系统框架。
API 还未实现对 `handleInitPackageResources``initZygote` 的调用。
在未来会根据使用和需求人数加上这个功能,如有需求你也可以向我们提交 Pull Request 来贡献你的代码。
### 支持更多 Hook Framework ### 支持更多 Hook Framework

View File

@@ -22,6 +22,14 @@
[filename](public/ModuleApplication.md ':include') [filename](public/ModuleApplication.md ':include')
[filename](public/YukiModuleResources.md ':include')
[filename](public/YukiResources.md ':include')
[filename](public/YukiResForwarder.md ':include')
[filename](public/YukiXposedEvent.md ':include')
[filename](public/ComponentTypeFactory.md ':include') [filename](public/ComponentTypeFactory.md ':include')
[filename](public/GraphicsTypeFactory.md ':include') [filename](public/GraphicsTypeFactory.md ':include')
@@ -38,7 +46,9 @@
[filename](public/YukiBaseHooker.md ':include') [filename](public/YukiBaseHooker.md ':include')
[filename](public/YukiHookCreater.md ':include') [filename](public/YukiMemberHookCreater.md ':include')
[filename](public/YukiResourcesHookCreater.md ':include')
[filename](public/MethodFinder.md ':include') [filename](public/MethodFinder.md ':include')
@@ -55,3 +65,5 @@
[filename](public/VariousClass.md ':include') [filename](public/VariousClass.md ':include')
[filename](public/CurrentClass.md ':include') [filename](public/CurrentClass.md ':include')
[filename](public/HookResources.md ':include')

View File

@@ -1,7 +1,7 @@
## ConstructorFinder [class] ## ConstructorFinder [class]
```kotlin ```kotlin
class ConstructorFinder(override val hookInstance: YukiHookCreater.MemberHookCreater?, override val classSet: Class<*>) : BaseFinder() class ConstructorFinder(override val hookInstance: YukiMemberHookCreater.MemberHookCreater?, override val classSet: Class<*>) : BaseFinder()
``` ```
**变更记录** **变更记录**
@@ -112,6 +112,22 @@ fun paramCount(num: Int): IndexTypeCondition
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。 !> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### superClass [method]
```kotlin
fun superClass(isOnlySuperClass: Boolean)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置在 `classSet` 的所有父类中查找当前 `Constructor`。
!> 若当前 `classSet` 的父类较多可能会耗时API 会自动循环到父类继承是 `Any` 前的最后一个类。
### RemedyPlan [class] ### RemedyPlan [class]
```kotlin ```kotlin

View File

@@ -1,7 +1,7 @@
## CurrentClass [class] ## CurrentClass [class]
```kotlin ```kotlin
class CurrentClass(private val instance: Class<*>, private val self: Any) class CurrentClass(internal val instance: Class<*>, internal val self: Any)
``` ```
**变更记录** **变更记录**
@@ -12,10 +12,24 @@ class CurrentClass(private val instance: Class<*>, private val self: Any)
> 当前实例的类操作对象。 > 当前实例的类操作对象。
### superClass [method]
```kotlin
fun superClass(): SuperClass
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 调用父类实例。
### field [method] ### field [method]
```kotlin ```kotlin
fun field(initiate: FieldFinder.() -> Unit): FieldFinder.Result.Instance inline fun field(initiate: FieldFinder.() -> Unit): FieldFinder.Result.Instance
``` ```
**变更记录** **变更记录**
@@ -29,7 +43,7 @@ fun field(initiate: FieldFinder.() -> Unit): FieldFinder.Result.Instance
### method [method] ### method [method]
```kotlin ```kotlin
fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result.Instance inline fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result.Instance
``` ```
**变更记录** **变更记录**
@@ -39,3 +53,45 @@ fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result.Instance
**功能描述** **功能描述**
> 调用当前实例中的方法。 > 调用当前实例中的方法。
### SuperClass [class]
```kotlin
inner class SuperClass
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 当前类的父类实例的类操作对象。
#### field [method]
```kotlin
inline fun field(initiate: FieldFinder.() -> Unit): FieldFinder.Result.Instance
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 调用父类实例中的变量。
#### method [method]
```kotlin
inline fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result.Instance
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 调用父类实例中的方法。

View File

@@ -1,7 +1,7 @@
## FieldFinder [class] ## FieldFinder [class]
```kotlin ```kotlin
class FieldFinder(override val hookInstance: YukiHookCreater.MemberHookCreater?, override val classSet: Class<*>?) : BaseFinder() class FieldFinder(override val hookInstance: YukiMemberHookCreater.MemberHookCreater?, override val classSet: Class<*>?) : BaseFinder()
``` ```
**变更记录** **变更记录**
@@ -132,6 +132,22 @@ fun type(value: Any): IndexTypeCondition
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。 !> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### superClass [method]
```kotlin
fun superClass(isOnlySuperClass: Boolean)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置在 `classSet` 的所有父类中查找当前 `Field`。
!> 若当前 `classSet` 的父类较多可能会耗时API 会自动循环到父类继承是 `Any` 前的最后一个类。
### Result [class] ### Result [class]
```kotlin ```kotlin

View File

@@ -1,7 +1,7 @@
## HookParam [class] ## HookParam [class]
```kotlin ```kotlin
class HookParam(private val createrInstance: YukiHookCreater, private val wrapper: HookParamWrapper) class HookParam(private val createrInstance: YukiMemberHookCreater, private var wrapper: HookParamWrapper?)
``` ```
**变更记录** **变更记录**

View File

@@ -0,0 +1,13 @@
## HookResources [class]
```kotlin
class HookResources(var instance: YukiResources?)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 创建一个当前 Hook 的 `YukiResources` 接管类。

View File

@@ -49,3 +49,41 @@ fun onHook()
**功能描述** **功能描述**
> Xposed API 的模块装载调用入口方法。 > Xposed API 的模块装载调用入口方法。
### onXposedEvent [method]
```kotlin
fun onXposedEvent()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 监听 Xposed 原生装载事件。
若你的 Hook 事件中存在需要兼容的原生 Xposed 功能,可在这里实现。
请在这里使用 `YukiXposedEvent` 创建回调事件监听。
可监听的事件如下:
`YukiXposedEvent.onInitZygote`
`YukiXposedEvent.onHandleLoadPackage`
`YukiXposedEvent.onHandleInitPackageResources`
!> 此接口仅供监听和实现原生 Xposed API 的功能,请不要在这里操作 `YukiHookAPI`
## ~~YukiHookXposedInitProxy [interface]~~ <!-- {docsify-ignore} -->
**变更记录**
`v1.0` `添加`
`v1.0.80` `作废`
请转移到 `IYukiHookXposedInit`

View File

@@ -1,7 +1,7 @@
## MethodFinder [class] ## MethodFinder [class]
```kotlin ```kotlin
class MethodFinder(override val hookInstance: YukiHookCreater.MemberHookCreater?, override val classSet: Class<*>) : BaseFinder() class MethodFinder(override val hookInstance: YukiMemberHookCreater.MemberHookCreater?, override val classSet: Class<*>) : BaseFinder()
``` ```
**变更记录** **变更记录**
@@ -196,6 +196,22 @@ fun returnType(value: Any): IndexTypeCondition
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。 !> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### superClass [method]
```kotlin
fun superClass(isOnlySuperClass: Boolean)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置在 `classSet` 的所有父类中查找当前 `Method`。
!> 若当前 `classSet` 的父类较多可能会耗时API 会自动循环到父类继承是 `Any` 前的最后一个类。
### RemedyPlan [class] ### RemedyPlan [class]
```kotlin ```kotlin

View File

@@ -1,7 +1,7 @@
## PackageParam [class] ## PackageParam [class]
```kotlin ```kotlin
open class PackageParam(private var wrapper: PackageParamWrapper?) open class PackageParam(internal var wrapper: PackageParamWrapper?)
``` ```
**变更记录** **变更记录**
@@ -54,6 +54,24 @@ val appContext: Application
> 获取当前 Hook APP 的 `Application`。 > 获取当前 Hook APP 的 `Application`。
!> 首次装载可能是空的,请延迟一段时间再获取。
### appResources [field]
```kotlin
val appResourcesResources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获取当前 Hook APP 的 Resources。
!> 你只能在 `HookResources.hook` 方法体内或 `appContext` 装载完毕时进行调用。
### processName [field] ### processName [field]
```kotlin ```kotlin
@@ -112,6 +130,38 @@ val mainProcessName: String
其对应的就是 `packageName` 其对应的就是 `packageName`
### moduleAppFilePath [field]
```kotlin
val moduleAppFilePath: String
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获取当前 Xposed 模块自身 APK 文件路径。
!> 作为 Hook API 装载时无法使用,会获取到空字符串。
### moduleAppResources [field]
```kotlin
val moduleAppResources: YukiModuleResources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获取当前 Xposed 模块自身 `Resources`。
!> 作为 Hook API 或不支持的 Hook Framework 装载时无法使用,会抛出异常。
### prefs [field] ### prefs [field]
```kotlin ```kotlin
@@ -126,6 +176,8 @@ val prefs: YukiHookModulePrefs
> 获得当前使用的存取数据对象缓存实例。 > 获得当前使用的存取数据对象缓存实例。
!> 作为 Hook API 装载时无法使用,会抛出异常。
### prefs [method] ### prefs [method]
```kotlin ```kotlin
@@ -146,6 +198,24 @@ fun prefs(name: String): YukiHookModulePrefs
你可以通过 `name` 来自定义 Sp 存储的名称。 你可以通过 `name` 来自定义 Sp 存储的名称。
!> 作为 Hook API 装载时无法使用,会抛出异常。
### resources [method]
```kotlin
fun resources(): HookResources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获得当前 Hook APP 的 `YukiResources` 对象。
请调用 `HookResources.hook` 方法开始 Hook。
### loadApp [method] ### loadApp [method]
```kotlin ```kotlin
@@ -170,6 +240,28 @@ fun loadApp(name: String, hooker: YukiBaseHooker)
`name` 为 APP 的包名,后方的两个参数一个可作为 `lambda` 方法体使用,一个可以直接装载子 Hooker。 `name` 为 APP 的包名,后方的两个参数一个可作为 `lambda` 方法体使用,一个可以直接装载子 Hooker。
装载并 Hook 指定、全部包名的 APP若要 Hook 系统框架,请使用 `loadZygote`
### loadZygote [method]
```kotlin
inline fun loadZygote(initiate: PackageParam.() -> Unit)
```
```kotlin
fun loadZygote(hooker: YukiBaseHooker)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 装载并 Hook 系统框架。
方法中的两个参数一个可作为 `lambda` 方法体使用,一个可以直接装载子 Hooker。
### withProcess [method] ### withProcess [method]
```kotlin ```kotlin
@@ -331,19 +423,19 @@ val variousClass = VariousClass("com.example.demo.DemoClass1", "com.example.demo
### hook [method] ### hook [method]
```kotlin ```kotlin
inline fun String.hook(isUseAppClassLoader: Boolean, initiate: YukiHookCreater.() -> Unit): YukiHookCreater.Result inline fun String.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result
``` ```
```kotlin ```kotlin
inline fun Class<*>.hook(isUseAppClassLoader: Boolean, initiate: YukiHookCreater.() -> Unit): YukiHookCreater.Result inline fun Class<*>.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result
``` ```
```kotlin ```kotlin
inline fun VariousClass.hook(isUseAppClassLoader: Boolean, initiate: YukiHookCreater.() -> Unit): YukiHookCreater.Result inline fun VariousClass.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result
``` ```
```kotlin ```kotlin
inline fun HookClass.hook(isUseAppClassLoader: Boolean, initiate: YukiHookCreater.() -> Unit): YukiHookCreater.Result inline fun HookClass.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result
``` ```
**变更记录** **变更记录**
@@ -360,7 +452,7 @@ inline fun HookClass.hook(isUseAppClassLoader: Boolean, initiate: YukiHookCreate
`v1.0.3` `修改` `v1.0.3` `修改`
新增 `YukiHookCreater.Result` 返回值 新增 `YukiMemberHookCreater.Result` 返回值
`v1.0.70` `修改` `v1.0.70` `修改`
@@ -444,3 +536,33 @@ YourClass.hook(isUseAppClassLoader = false) {
// Your code here. // Your code here.
} }
``` ```
### hook [method]
```kotlin
inline fun HookResources.hook(initiate: YukiResourcesHookCreater.() -> Unit)
```
**变更记录**
`v1.0.80` `新增
**功能描述**
> Hook APP 的 Resources。
**功能示例**
Resources Hook 为固定用法,获取 `resources` 对象,然后调用 `hook` 方法开始 Hook。
> 示例如下
```kotlin
resources().hook {
// Your code here.
}
```
!> 这是固定用法,为了防止发生问题,你不可手动实现任何 `HookResources` 实例执行 `hook` 调用。
将 Resources 的 Hook 设置为这样是为了与 `findClass(...).hook` 做到统一,使得调用起来逻辑不会混乱。

View File

@@ -8,6 +8,34 @@
> 这是自定义 `Member` 和 `Class` 相关功能的查找匹配以及 `invoke` 的封装类。 > 这是自定义 `Member` 和 `Class` 相关功能的查找匹配以及 `invoke` 的封装类。
### hookClass [field]
```kotlin
val Class<*>.hookClass: HookClass
```
**变更记录**
`v1.0` `添加`
**功能描述**
> 将 `Class` 转换为 `HookClass`。
### normalClass [field]
```kotlin
val HookClass.normalClass: Class<*>?
```
**变更记录**
`v1.0` `添加`
**功能描述**
> 将 `HookClass` 转换为 `Class`。
### hasClass [field] ### hasClass [field]
```kotlin ```kotlin
@@ -36,33 +64,19 @@ if("com.example.demo.DemoClass".hasClass) {
} }
``` ```
### hookClass [field] ### hasExtends [field]
```kotlin ```kotlin
val Class<*>.hookClass: HookClass val Class<*>.hasExtends: Boolean
``` ```
**变更记录** **变更记录**
`v1.0` `添加` `v1.0.80` `新增`
**功能描述** **功能描述**
> `Class` 转换为 `HookClass` > 当前 `Class` 是否有继承关系,父类是 `Any` 将被认为没有继承关系
### normalClass [field]
```kotlin
val HookClass.normalClass: Class<*>?
```
**变更记录**
`v1.0` `添加`
**功能描述**
> 将 `HookClass` 转换为 `Class`。
### classOf [method] ### classOf [method]

View File

@@ -50,7 +50,21 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker)
**功能描述** **功能描述**
> 在 `IYukiHookXposedInit` 中装载 `YukiHookAPI`。 > 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。
### resources [method]
```kotlin
fun IYukiHookXposedInit.resources(initiate: ResourcesParam.() -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI.resources`。
### modulePrefs [field] ### modulePrefs [field]
@@ -94,6 +108,20 @@ val Context.processName: String
> 获取当前进程名称。 > 获取当前进程名称。
### isSupportResourcesHook [field]
```kotlin
val Any?.isSupportResourcesHook: Boolean
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 判断当前 Hook Framework 是否支持资源钩子(Resources Hook)。
### isModuleActive [field] ### isModuleActive [field]
```kotlin ```kotlin

View File

@@ -1,7 +1,7 @@
## YukiHookCreater [class] ## YukiMemberHookCreater [class]
```kotlin ```kotlin
class YukiHookCreater(private val packageParam: PackageParam, internal val hookClass: HookClass) class YukiMemberHookCreater(private val packageParam: PackageParam, internal val hookClass: HookClass)
``` ```
**变更记录** **变更记录**
@@ -14,7 +14,49 @@ class YukiHookCreater(private val packageParam: PackageParam, internal val hookC
**功能描述** **功能描述**
> `YukiHookAPI` 核心 Hook 实现类。 > `YukiHookAPI``Member` 核心 Hook 实现类。
### PRIORITY_DEFAULT [field]
```kotlin
val PRIORITY_DEFAULT: Int
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 默认 Hook 回调优先级。
### PRIORITY_LOWEST [field]
```kotlin
val PRIORITY_LOWEST: Int
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 延迟回调 Hook 方法结果。
### PRIORITY_HIGHEST [field]
```kotlin
val PRIORITY_HIGHEST: Int
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 更快回调 Hook 方法结果。
### instanceClass [field] ### instanceClass [field]
@@ -39,7 +81,7 @@ val instanceClass: Class<*>
### injectMember [method] ### injectMember [method]
```kotlin ```kotlin
inline fun injectMember(tag: String, initiate: MemberHookCreater.() -> Unit): MemberHookCreater.Result inline fun injectMember(priority: Int, tag: String, initiate: MemberHookCreater.() -> Unit): MemberHookCreater.Result
``` ```
**变更记录** **变更记录**
@@ -50,6 +92,8 @@ inline fun injectMember(tag: String, initiate: MemberHookCreater.() -> Unit): Me
将方法体进行 inline 将方法体进行 inline
增加 `priority` Hook 优先级
**功能描述** **功能描述**
> 注入要 Hook 的方法、构造类。 > 注入要 Hook 的方法、构造类。
@@ -76,16 +120,30 @@ injectMember(tag = "KuriharaYuki") {
} }
``` ```
你还可以自定义 `priority`,以控制当前 Hook 对象并列执行的优先级速度。
> 示例如下
```kotlin
injectMember(priority = PRIORITY_HIGHEST) {
// Your code here.
}
```
### MemberHookCreater [class] ### MemberHookCreater [class]
```kotlin ```kotlin
inner class MemberHookCreater(var tag: String) inner class MemberHookCreater(private val priority: Int, internal val tag: String)
``` ```
**变更记录** **变更记录**
`v1.0` `添加` `v1.0` `添加`
`v1.0.80` `修改`
增加 `priority` Hook 优先级
**功能描述** **功能描述**
> Hook 核心功能实现类,查找和处理需要 Hook 的方法、构造类。 > Hook 核心功能实现类,查找和处理需要 Hook 的方法、构造类。

View File

@@ -0,0 +1,29 @@
## YukiModuleResources [class]
```kotlin
class YukiModuleResources(private val baseInstance: XModuleResources) : Resources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 对接 `XModuleResources` 的中间层实例。
### fwd [method]
```kotlin
fun fwd(resId: Int): YukiResForwarder
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 对接 `XModuleResources.fwd` 方法。
创建 `YukiResForwarder``XResForwarder` 实例。

View File

@@ -0,0 +1,55 @@
## YukiResForwarder [class]
```kotlin
class YukiResForwarder(private val baseInstance: XResForwarder)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 对接 `XResForwarder` 的中间层实例。
### instance [field]
```kotlin
val instance: XResForwarder
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获得 `XResForwarder` 实例。
### id [field]
```kotlin
val id: Int
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获得当前 APP 的 Resources Id。
### resources [field]
```kotlin
val resources: Resources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获得当前 APP 的 Resources。

View File

@@ -0,0 +1,77 @@
## YukiResources [class]
```kotlin
class YukiResources(private val baseInstance: XResources) : Resources
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 对接 `XResources` 的中间层实例。
### LayoutInflatedParam [class]
```kotlin
class LayoutInflatedParam(internal val baseParam: XC_LayoutInflated.LayoutInflatedParam)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 装载 Hook APP 的目标布局 Resources 实现类。
#### variantName [field]
```kotlin
val variantName: String
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获取当前被 Hook 的布局装载目录名称。
例如:`layout``layout-land``layout-sw600dp`
#### currentView [field]
```kotlin
val currentView: View
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 获取当前被 Hook 的布局实例。
#### findViewByIdentifier [method]
```kotlin
inline fun <reified T : View> View.findViewByIdentifier(name: String): T?
```
```kotlin
inline fun <reified T : View> findViewByIdentifier(name: String): T?
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 使用 Identifier 查找 Hook APP 指定 Id 的 `View`。
扩展方法可以使用 Identifier 查找 Hook APP 当前装载布局中指定 Id 的 `View`

View File

@@ -0,0 +1,569 @@
## YukiResourcesHookCreater [class]
```kotlin
class YukiResourcesHookCreater(private val packageParam: PackageParam, internal val hookResources: HookResources)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> `YukiHookAPI` 的 `Resources` 核心 Hook 实现类。
### injectResource [method]
```kotlin
inline fun injectResource(tag: String, initiate: ResourceHookCreater.() -> Unit): ResourceHookCreater.Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 注入要 Hook 的 Resources。
**功能示例**
你可以注入任意 Resources使用 `injectResource` 即可创建一个 `Hook` 对象。
> 示例如下
```kotlin
injectResource {
// Your code here.
}
```
你还可以自定义 `tag`,方便你在调试的时候能够区分你的 `Hook` 对象。
> 示例如下
```kotlin
injectResource(tag = "KuriharaYuki") {
// Your code here.
}
```
### ResourcesHookCreater [class]
```kotlin
inner class ResourcesHookCreater(private val tag: String)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> Hook 核心功能实现类。
查找和处理需要 Hook 的 Resources。
#### resourceId [field]
```kotlin
var resourceId: Int
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 直接设置需要替换的 Resources Id。
!> 不建议使用此方法设置目标需要 Hook 的 Resources Id你可以使用 `conditions` 方法。
**功能示例**
你可以直接设置并指定目标 Hook APP 的 Resources Id。
> 示例如下
```kotlin
injectResource {
resourceId = 0x7f060001.toInt()
replaceTo(...)
}
```
#### conditions [method]
```kotlin
inline fun conditions(initiate: ConditionFinder.() -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 查找条件。
若你设置了 `resourceId` 则此方法将不会被使用。
**功能示例**
你可参考 [ConditionFinder](#conditionfinder-class) 查看详细用法。
> 示例如下
```kotlin
injectResource {
conditions {
name = "test_string"
string()
}
replaceTo(...)
}
```
#### replaceTo [method]
```kotlin
fun replaceTo(any: Any)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 替换指定 Resources 为指定的值。
**功能示例**
你可以替换找到的 Resources 为你想要的值,可以是 `String``Drawable` 等。
比如我们要替换一个找到的字符串 Resources。
> 示例如下
```kotlin
injectResource {
conditions {
name = "test_string"
string()
}
replaceTo("replace string")
}
```
或是替换为一个 `Drawable`,你无需对目标 Resources 实现 `fwd` 方法或 `DrawableLoader`
> 示例如下
```kotlin
injectResource {
conditions {
name = "test_drawable"
drawable()
}
replaceTo(ColorDrawable(Color.RED))
}
```
#### replaceToTrue [method]
```kotlin
fun replaceToTrue()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 替换指定 Resources 为 `true`。
!> 确保目标替换 Resources 的类型为 `Boolean`
#### replaceToFalse [method]
```kotlin
fun replaceToFalse()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 替换指定 Resources 为 `false`。
!> 确保目标替换 Resources 的类型为 `Boolean`
#### replaceToModuleResource [method]
```kotlin
fun replaceToModuleResource(resId: Int)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的 `R.string.xxx``R.mipmap.xxx``R.drawable.xxx` 替换 Hook APP 的 Resources。
**功能示例**
使用此方法可非常方便地使用当前模块的 Resources 去替换目标 Hook APP 的 Resources。
这个过程你无需对目标 Resources 实现 `fwd` 方法。
比如我们要替换一个字符串。
> 示例如下
```kotlin
injectResource {
conditions {
name = "test_string"
string()
}
replaceToModuleResource(R.id.module_string)
}
```
还可以替换一些复杂的 Resources比如 `xml` 创建的 `drawable`
> 示例如下
```kotlin
injectResource {
conditions {
name = "test_drawable"
drawable()
}
replaceToModuleResource(R.drawable.module_drawable)
}
```
#### injectAsLayout [method]
```kotlin
fun injectAsLayout(initiate: YukiResources.LayoutInflatedParam.() -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 作为装载的布局注入。
**功能示例**
你可以直接注入一个布局监听并修改它的内部 `View`
> 示例如下
```kotlin
injectResource {
conditions {
name = "activity_main"
layout()
}
injectAsLayout {
findViewByIdentifier<View>(name = "test_view")?.isVisible = false
findViewByIdentifier<TextView>(name = "test_text_view")?.text = "Hook this"
}
}
```
你还可以通过 `currentView` 拿到 `Context`
> 示例如下
```kotlin
injectResource {
conditions {
name = "activity_main"
layout()
}
injectAsLayout {
Toast.makeText(currentView.context, "Hook this", Toast.LENGTH_SHORT).show()
}
}
```
#### ConditionFinder [class]
```kotlin
inner class ConditionFinder
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> Resources 查找条件实现类。
##### name [field]
```kotlin
var name: String
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 名称。
##### anim [method]
```kotlin
fun anim()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为动画。
##### animator [method]
```kotlin
fun animator()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为属性动画。
##### bool [method]
```kotlin
fun bool()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为布朗(Boolean)。
##### color [method]
```kotlin
fun color()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为颜色(Color)。
##### dimen [method]
```kotlin
fun dimen()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为尺寸(Dimention)。
##### drawable [method]
```kotlin
fun drawable()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为 Drawable。
##### integer [method]
```kotlin
fun integer()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为整型(Integer)。
##### layout [method]
```kotlin
fun layout()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为布局(Layout)。
##### plurals [method]
```kotlin
fun plurals()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为 Plurals。
##### string [method]
```kotlin
fun string()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为字符串(String)。
##### xml [method]
```kotlin
fun xml()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为 Xml。
##### mipmap [method]
```kotlin
fun mipmap()
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 Resources 类型为位图(Mipmap)。
#### Result [class]
```kotlin
inner class Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 监听全部 Hook 结果实现类,可在这里处理失败事件监听。
##### result [method]
```kotlin
inline fun result(initiate: Result.() -> Unit): Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 创建监听事件方法体。
##### by [method]
```kotlin
inline fun by(initiate: () -> Boolean): Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
#### onHookingFailure [method]
```kotlin
fun onHookingFailure(initiate: (Throwable) -> Unit): Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 监听 Hook 过程发生错误的回调方法。
#### ignoredHookingFailure [method]
```kotlin
fun ignoredHookingFailure(): Result
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 忽略 Hook 过程出现的错误。

View File

@@ -0,0 +1,69 @@
## YukiXposedEvent [object]
```kotlin
object YukiXposedEvent
```
**变更记录**
`v1.0.80` `添加`
**功能描述**
> 实现对原生 Xposed API 的装载事件监听。
### events [method]
```kotlin
inline fun events(initiate: YukiXposedEvent.() -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 对 `YukiXposedEvent` 创建一个方法体。
### onInitZygote [method]
```kotlin
fun onInitZygote(initiate: (StartupParam) -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 initZygote 事件监听。
### onHandleLoadPackage [method]
```kotlin
fun onHandleLoadPackage(initiate: (LoadPackageParam) -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 handleLoadPackage 事件监听。
### onHandleInitPackageResources [method]
```kotlin
fun onHandleInitPackageResources(initiate: (InitPackageResourcesParam) -> Unit)
```
**变更记录**
`v1.0.80` `新增`
**功能描述**
> 设置 handleInitPackageResources 事件监听。

View File

@@ -177,6 +177,57 @@ class HookEntryClass : IYukiHookXposedInit {
} }
``` ```
### 扩展特性
如果你当前使用的 Hook Framework 支持并启用了资源钩子(Resources Hook)功能,你现在可以直接在 `encase` 中创建 Resources Hook。
你完全不需要与之前在使用 Xposed API 那样区分 `initZygote``handleLoadPackage``handleInitPackageResources` 方法来执行不同的功能。
`YukiHookAPI` 中,这些功能**是无缝的**。
> 示例如下
```kotlin
encase {
loadApp(name = "com.example.demo") {
findClass(name = "$packageName.DemoClass").hook {
// Your code here.
}
// 创建一个 Resources Hook (固定用法)
resources().hook {
// Your code here.
}
}
}
```
你还可以同时使用 `loadZygote` 方法来装载系统框架。
> 示例如下
```kotlin
encase {
loadZygote {
ActivityClass.hook {
// Your code here.
}
// 在 Zygote 中创建 Resources Hook
resources().hook {
// Your code here.
}
}
loadApp(name = "com.example.demo") {
findClass(name = "$packageName.DemoClass").hook {
// Your code here.
}
// 在 APP 中创建 Resources Hook
resources().hook {
// Your code here.
}
}
}
```
## 作为 Hook API 使用需要注意的地方 ## 作为 Hook API 使用需要注意的地方
若你作为 Hook API 使用,那么你只需要在入口处对 `encase` 方法进行区分。 若你作为 Hook API 使用,那么你只需要在入口处对 `encase` 方法进行区分。
@@ -197,3 +248,5 @@ fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
此处的 `baseContext` 只需填入你在 `attachBaseContext` 处得到的 `Context` 即可,其它用法与上述内容完全一致。 此处的 `baseContext` 只需填入你在 `attachBaseContext` 处得到的 `Context` 即可,其它用法与上述内容完全一致。
!> 切勿以 Xposed 方式使用 `encase` 方法而漏掉 `baseContext` 参数,否则你的 Hook 将完全不工作。 !> 切勿以 Xposed 方式使用 `encase` 方法而漏掉 `baseContext` 参数,否则你的 Hook 将完全不工作。
!> Resources Hook 功能不支持作为 Hook API 使用。

View File

@@ -16,11 +16,11 @@
请确认你在正确的地方装载了 `YukiHookAPI``encase` 方法,详情请参考 [作为 Xposed 模块使用的相关配置](config/xposed-using) 以及 [作为 Hook API 使用的相关配置](config/api-using)。 请确认你在正确的地方装载了 `YukiHookAPI``encase` 方法,详情请参考 [作为 Xposed 模块使用的相关配置](config/xposed-using) 以及 [作为 Hook API 使用的相关配置](config/api-using)。
!> `loggerE` You cannot load a hooker in "onInit" method! Aborted !> `loggerE` You cannot load a hooker in "onInit" or "onXposedEvent" method! Aborted
**异常原因** **异常原因**
你尝试在继承 `IYukiHookXposedInit` 的 Hook 入口类的 `onInit` 方法中装载了 `encase` 方法。 你尝试在继承 `IYukiHookXposedInit` 的 Hook 入口类的 `onInit` `onXposedEvent` 方法中装载了 `encase``resources` 方法。
> 示例如下 > 示例如下
@@ -34,6 +34,13 @@ class HookEntry : IYukiHookXposedInit {
} }
} }
override fun onXposedEvent() {
// ❗错误的使用方法
YukiHookAPI.encase {
// Your code here.
}
}
override fun onHook() { override fun onHook() {
// Your code here. // Your code here.
} }
@@ -75,6 +82,16 @@ class HookEntry : IYukiHookXposedInit {
通常情况下这种错误不会轻易发生,若一旦发生此错误,请自行查看控制台打印的日志定位问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。 通常情况下这种错误不会轻易发生,若一旦发生此错误,请自行查看控制台打印的日志定位问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。
!> `loggerE` YukiHookAPI bind initZygote failed
**异常原因**
`YukiHookAPI` 在尝试装载 Xposed 原生接口 `initZygote` 方法时发生了不能处理的异常。
**解决方案**
通常情况下这种错误不会轻易发生,若一旦发生此错误,请自行查看控制台打印的日志定位问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。
!> `loggerE` HookClass \[**NAME**\] not found !> `loggerE` HookClass \[**NAME**\] not found
**异常原因** **异常原因**
@@ -361,6 +378,50 @@ method {
请检查查询条件中 `param``index` 号下标的 `Class` 是否存在,然后再试一次。 请检查查询条件中 `param``index` 号下标的 `Class` 是否存在,然后再试一次。
!> `loggerE` Resources Hook condition name/type cannot be empty \[**TAG**\]
**异常原因**
在查找 Resources 时并未设置任何条件。
> 示例如下
```kotlin
// 情况 1
conditions {
// 这里没有设置任何条件
}
// 情况 2
conditions {
name = "test"
// 这里缺少了 type 条件
}
```
**解决方案**
Resources 的 Hook 并非类似方法的 Hook其必须拥有完整的名称和类型描述才能查询成功请将查询条件补充完整并再试一次。
!> `loggerE` Resources Hook type is invalid \[**TAG**\]
**异常原因**
在 Hook Resources 时发生了类型错误的异常。
**解决方案**
`YukiHookAPI` 会尝试在 `initZygote``handleInitPackageResources` 中装载 Resources Hook若全部装载失败可能会发生此异常当前 Hook Framework 需要支持并启用资源钩子(Resources Hook)功能,请检查后再试一次。
!> `loggerE` Resources Hook got an Exception \[**TAG**\]
**异常原因**
在 Hook Resources 时发生了任意的异常。
**解决方案**
这是一个异常汇总,请自行向下查看日志具体的异常是什么,例如找不到 Resources Id 的问题。
## 阻断异常 ## 阻断异常
> 这些异常会直接导致 APP 停止运行(FC),同时会在控制台打印 `E` 级别的日志,还会造成 Hook 进程“死掉”。 > 这些异常会直接导致 APP 停止运行(FC),同时会在控制台打印 `E` 级别的日志,还会造成 Hook 进程“死掉”。
@@ -682,6 +743,42 @@ encase {
`appContext` 在宿主环境初始化完成之前有大的概率可能是空的,请延迟获取或在宿主的 Hook 方法回调方法体内再使用此变量。 `appContext` 在宿主环境初始化完成之前有大的概率可能是空的,请延迟获取或在宿主的 Hook 方法回调方法体内再使用此变量。
!> `IllegalStateException` Current Hook Framework not support moduleAppResources
**异常原因**
`PackageParam` 中调用了 `moduleAppResources` 变量但是无法获取到实例对象。
> 示例如下
```kotlin
encase {
// 调用了此变量
moduleAppResources...
}
```
**解决方案**
`moduleAppResources` 需要当前 Hook Framework 支持 `initZygote` 功能,请检查后再试一次。
!> `IllegalStateException` You cannot call to appResources in this time
`PackageParam` 中调用了 `appResources` 变量但是无法获取到实例对象。
> 示例如下
```kotlin
encase {
// 调用了此变量
appResources...
}
```
**解决方案**
`appResources` 不会在 `initZygote` 中装载,另外,这个功能需要当前 Hook Framework 支持并启用资源钩子(Resources Hook)功能,请检查后再试一次。
!> `IllegalStateException` VariousClass match failed of those **CLASSES** !> `IllegalStateException` VariousClass match failed of those **CLASSES**
**异常原因** **异常原因**
@@ -713,6 +810,48 @@ TargetClass.hook {
详情请参考 [状态监听](guide/example?id=状态监听)。 详情请参考 [状态监听](guide/example?id=状态监听)。
!> `IllegalStateException` LayoutInflatedParam View instance got null
**异常原因**
在布局 Hook 回调中调用了 `currentView` 但没取到实例对象。
> 示例如下
```kotlin
injectResource {
conditions {
name = "activity_main"
layout()
}
injectAsLayout {
// 调用了此变量
currentView...
}
}
```
**解决方案**
这种情况基本上不存在,除非被 Hook 的宿主当前 `Activity` 已经销毁或 Hook Framework 自身存在问题。
!> `IllegalStateException` XResForwarder is invalid
**异常原因**
`YukiResForwarder` 中调用了 `resources` 但没取到实例对象。
> 示例如下
```kotlin
// 调用了此变量
moduleAppResources.fwd(...).resources
```
**解决方案**
这种情况基本上不存在,除非 Hook Framework 自身存在问题。
!> `IllegalStateException` Hook Members is empty, hook aborted !> `IllegalStateException` Hook Members is empty, hook aborted
**异常原因** **异常原因**
@@ -731,6 +870,24 @@ TargetClass.hook {
你必须在 `hook` 方法体内加入至少一个 `injectMember` 方法。 你必须在 `hook` 方法体内加入至少一个 `injectMember` 方法。
!> `IllegalStateException` Hook Resources is empty, hook aborted
**异常原因**
使用了 `hook` 方法体但其中并没有填写内容。
> 示例如下
```kotlin
resources().hook {
// 这里没有填写任何内容
}
```
**解决方案**
你必须在 `hook` 方法体内加入至少一个 `injectResources` 方法。
!> `IllegalStateException` paramTypes is empty, please use emptyParam() instead !> `IllegalStateException` paramTypes is empty, please use emptyParam() instead
**异常原因** **异常原因**
@@ -772,3 +929,13 @@ method {
paramCount = 0 paramCount = 0
} }
``` ```
!> `IllegalStateException` Invalid YukiHookCallback type
**异常原因**
`YukiHookAPI` 的核心 Hook 功能发生故障。
**解决方案**
这种情况基本上不存在,若发生上述问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。

View File

@@ -10,16 +10,7 @@
> ~~如果你仍然在使用 `Proguard`,你需要做一些规则配置。~~ > ~~如果你仍然在使用 `Proguard`,你需要做一些规则配置。~~
~~在 `proguard-rules.pro` 添加如下代码即可。~~ !> Proguard 规则已被弃用,请不要再使用,自从 Android Gradle Plugin 4.2 后,拥有 Android Jetpack 套件最新版本的混淆处理程序默认均为 `R8`,不再需要考虑混淆的问题。
> ~~示例如下~~
```proguard
-keep class com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus {*;}
-keep class 这里填你的 HookEntryClass 入口类完整包名_YukiHookXposedInit {*;}
```
!> Proguard 规则已被弃用,请不要再使用,自从 Android Gradle Plugin 4.2 后,拥有 Android Jetpack 套件最新版本的混淆处理程序默认均为 `R8`,基本可以不需要考虑混淆的问题。
若要在任何版本下启用 `R8`,请在 `gradle.properties` 文件中加入如下规则Android Gradle Plugin 7.0 及以上版本无需任何配置。 若要在任何版本下启用 `R8`,请在 `gradle.properties` 文件中加入如下规则Android Gradle Plugin 7.0 及以上版本无需任何配置。

View File

@@ -96,7 +96,7 @@ Xposed 入口类处理如下。
> 示例如下 > 示例如下
```kotlin ```kotlin
class HookEntry_YukiHookXposedInit: IXposedHookLoadPackage, ... class HookEntry_YukiHookXposedInit: IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources
``` ```
编译后的类名结构如下。 编译后的类名结构如下。
@@ -105,6 +105,7 @@ class HookEntry_YukiHookXposedInit: IXposedHookLoadPackage, ...
``` ```
...hook.HookEntry ← 你的入口类 ...hook.HookEntry ← 你的入口类
...hook.HookEntry_Impl ← 自动生成的 Impl 类
...hook.HookEntry_YukiHookXposedInit ← 自动生成的 Xposed 入口类 ...hook.HookEntry_YukiHookXposedInit ← 自动生成的 Xposed 入口类
``` ```
@@ -122,7 +123,7 @@ Xposed 入口类处理如下。
> 示例如下 > 示例如下
```kotlin ```kotlin
class HookXposedEntry: IXposedHookLoadPackage, ... class HookXposedEntry: IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources
``` ```
编译后的类名结构如下。 编译后的类名结构如下。
@@ -131,6 +132,7 @@ class HookXposedEntry: IXposedHookLoadPackage, ...
``` ```
...hook.HookEntry ← 你的入口类 ...hook.HookEntry ← 你的入口类
...hook.HookEntry_Impl ← 自动生成的 Impl 类
...hook.HookXposedEntry ← 自动生成的 Xposed 入口类 ...hook.HookXposedEntry ← 自动生成的 Xposed 入口类
``` ```
@@ -138,21 +140,47 @@ class HookXposedEntry: IXposedHookLoadPackage, ...
### IYukiHookXposedInit 接口 ### IYukiHookXposedInit 接口
```kotlin
interface IYukiHookXposedInit {
fun onInit()
fun onHook()
}
```
`IYukiHookXposedInit` 接口为你的 `HookEntryClass` 必须实现的接口,这是你的模块开始 Hook 的起点。 `IYukiHookXposedInit` 接口为你的 `HookEntryClass` 必须实现的接口,这是你的模块开始 Hook 的起点。
若要了解更多可 [点击这里](api/document?id=iyukihookxposedinit-interface) 进行查看。 若要了解更多可 [点击这里](api/document?id=iyukihookxposedinit-interface) 进行查看。
当你的模块被 Xposed 装载后,`onHook` 方法将会被回调,你需要在此方法中开始使用 `YukiHookAPI` 当你的模块被 Xposed 装载后,`onHook` 方法将会被回调,你需要在此方法中开始使用 `YukiHookAPI`
> 基本的调用流程为 `YukiHookInjectXposedInitClass.handleLoadPackage` → `HookEntryClass.onInit` → `HookEntryClass.onHook` → `YukiHookAPI.onXposedLoaded` > 基本的调用流程为 `_YukiHookXposedInit` → `IYukiHookXposedInit.onXposedEvent` → `IYukiHookXposedInit.onInit` → `IYukiHookXposedInit.onHook`
详情请参考 [API 基本配置](config/api-example)。 详情请参考 [API 基本配置](config/api-example)。
## 原生 Xposed API 事件
若你当前的 Xposed 模块使用了第三方的资源,但是短时间内可能无法转移它们,此时,你可以使用 `onXposedEvent` 实现监听原生 Xposed API 的全部装载事件。
> 示例如下
```kotlin
@InjectYukiHookWithXposed
class HookEntry: IYukiHookXposedInit {
override fun onHook() {
// Your code here.
}
override fun onXposedEvent() {
// 监听原生 Xposed API 的装载事件
YukiXposedEvent.events {
onInitZygote {
// it 对象即 [StartupParam]
}
onHandleLoadPackage {
// it 对象即 [LoadPackageParam]
}
onHandleInitPackageResources {
// it 对象即 [InitPackageResourcesParam]
}
}
}
}
```
`onXposedEvent``onHook` 方法完全独立存在,互不影响,你可以继续在 `onHook` 方法中使用 `YukiHookAPI`
若要了解更多可 [点击这里](api/document?id=onxposedevent-method) 进行查看。

View File

@@ -8,7 +8,7 @@
``` ```
Host Environment Host Environment
└── YukiHookCreater └── YukiMemberHookCreater
└── Class └── Class
└── MemberHookCreater └── MemberHookCreater
└── Member └── Member
@@ -19,6 +19,15 @@ Host Environment
├── Before ├── Before
└── After └── After
... ...
YukiResourcesHookCreater
└── Resources
└── ResourcesHookCreater
└── Drawable
└── Replace
ResourcesHookCreater
└── Layout
└── Inject
...
``` ```
> 上方的结构换做代码将可写为如下形式。 > 上方的结构换做代码将可写为如下形式。
@@ -37,6 +46,14 @@ TargetClass.hook {
} }
} }
} }
resources().hook {
injectResource {
conditions {
// Your code here.
}
replaceTo(...)
}
}
``` ```
## Demo ## Demo
@@ -51,6 +68,10 @@ TargetClass.hook {
## 一个简单的 Hook 例子 ## 一个简单的 Hook 例子
> 这里给出了 Hook APP、Hook 系统框架与 Hook Resources 的例子,可供参考。
### Hook APP
假设,我们要 Hook `com.android.browser` 中的 `onCreate` 方法并弹出一个对话框。 假设,我们要 Hook `com.android.browser` 中的 `onCreate` 方法并弹出一个对话框。
`encase` 方法体中添加代码。 `encase` 方法体中添加代码。
@@ -171,6 +192,97 @@ TestClass.hook {
} }
``` ```
### Hook 系统框架
`YukiHookAPI`Hook 系统框架的实现非常简单。
假设我们要全局 Hook 一个 `Activity``onCreate` 事件
`encase` 方法体中添加代码。
> 示例如下
```kotlin
loadZygote {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
returnType = UnitType
}
afterHook {
// Your code here.
}
}
}
}
```
这样就实现了上述的 Hook 功能。
!> `loadZygote``loadApp(name = "android")` 有直接性区别,`loadZygote` 会在 `initZygote` 中装载,若要 Hook 系统框架,建议使用 `loadZygote`
### Hook Resources
假设,我们要 Hook `com.android.browser``string` 类型的 `app_name` 内容替换为 `123`
`encase` 方法体中添加代码。
> 示例如下
```kotlin
loadApp(name = "com.android.browser") {
resources().hook {
injectResource {
conditions {
name = "app_name"
string()
}
replaceTo("123")
}
}
}
```
若当前 APP 使用 `app_name` 设置了标题栏文本,则它就会变成我们的 `123`
你还可以使用当前 Xposed 模块的 Resources 替换 Hook APP 的 Resources。
假设,我们要继续 Hook `com.android.browser``mipmap` 类型的 `ic_launcher`
> 示例如下
```kotlin
loadApp(name = "com.android.browser") {
resources().hook {
injectResource {
conditions {
name = "ic_launcher"
mipmap()
}
replaceToModuleResource(R.mipmap.ic_launcher)
}
}
}
```
至此目标 APP 的图标将会被替换为我们设置的图标。
若你想替换系统框架的资源,同样也可以这样实现,只需要把 `loadApp` 换成 `loadZygote` 即可。
> 示例如下
```kotlin
loadZygote {
resources().hook {
// Your code here.
}
}
```
更多功能请参考 [ResourcesHookCreater](api/document?id=resourceshookcreater-class)。
## 异常处理 ## 异常处理
> `YukiHookAPI` 重新设计了对异常的监听,任何异常都不会在 Hook 过程中抛出,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。 > `YukiHookAPI` 重新设计了对异常的监听,任何异常都不会在 Hook 过程中抛出,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。
@@ -193,6 +305,20 @@ injectMember {
} }
``` ```
在 Resources Hook 时此方法同样适用。
> 示例如下
```kotlin
injectResource {
// Your code here.
}.result {
// 处理 Hook 时的任意异常
onHookingFailure {}
// ...
}
```
你还可以处理 Hook 的 `Class` 不存在时发生的异常。 你还可以处理 Hook 的 `Class` 不存在时发生的异常。
> 示例如下 > 示例如下

View File

@@ -62,6 +62,8 @@
现在,我们只需要编写少量的代码,一切时间开销和花费交给自动化处理。 现在,我们只需要编写少量的代码,一切时间开销和花费交给自动化处理。
借助 `Kotlin` 优雅的 `lambda` 写法以及 `YukiHookAPI`,可以让你的 Hook 逻辑更加美观清晰。
> 示例如下 > 示例如下
<!-- tabs:start --> <!-- tabs:start -->
@@ -70,9 +72,34 @@
```kotlin ```kotlin
@InjectYukiHookWithXposed @InjectYukiHookWithXposed
class MainHook : IYukiHookXposedInit { class HookEntry : IYukiHookXposedInit {
override fun onHook() = encase { override fun onHook() = encase {
loadZygote {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
beforeHook {
// Your code here.
}
afterHook {
// Your code here.
}
}
}
resources().hook {
injectResource {
conditions {
name = "sym_def_app_icon"
mipmap()
}
replaceToModuleResource(R.mipmap.ic_launcher)
}
}
}
loadApp(name = "com.android.browser") { loadApp(name = "com.android.browser") {
ActivityClass.hook { ActivityClass.hook {
injectMember { injectMember {
@@ -88,6 +115,15 @@ class MainHook : IYukiHookXposedInit {
} }
} }
} }
resources().hook {
injectResource {
conditions {
name = "ic_launcher"
mipmap()
}
replaceToModuleResource(R.mipmap.ic_launcher)
}
}
} }
} }
} }
@@ -96,14 +132,16 @@ class MainHook : IYukiHookXposedInit {
#### **Xposed API** #### **Xposed API**
```kotlin ```kotlin
class MainHook : IXposedHookLoadPackage { class HookEntry : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources {
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { private lateinit var moduleResources: XModuleResources
if (lpparam.packageName == "com.android.browser")
override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam) {
moduleResources = XModuleResources.createInstance(sparam.modulePath, null)
XResources.setSystemWideReplacement("android", "mipmap", "sym_def_app_icon", moduleResources.fwd(R.mipmap.ic_launcher))
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
Activity::class.java.name, Activity::class.java.name,
lpparam.classLoader, null, "onCreate",
"onCreate",
Bundle::class.java, Bundle::class.java,
object : XC_MethodHook() { object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam?) { override fun beforeHookedMethod(param: MethodHookParam?) {
@@ -115,14 +153,36 @@ class MainHook : IXposedHookLoadPackage {
} }
}) })
} }
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
if (lpparam.packageName == "com.android.browser")
XposedHelpers.findAndHookMethod(
Activity::class.java.name,
lpparam.classLoader, "onCreate",
Bundle::class.java,
object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam?) {
// Your code here.
}
override fun afterHookedMethod(param: MethodHookParam?) {
// Your code here.
}
})
}
override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam) {
if (resparam.packageName == "com.android.browser")
resparam.res.setReplacement("com.android.browser", "mipmap", "ic_launcher", moduleResources.fwd(R.mipmap.ic_launcher))
}
} }
``` ```
<!-- tabs:end --> <!-- tabs:end -->
是的,你没有看错,仅仅就需要这几行代码,就一切安排妥当 是的,你没有看错,仅仅就需要这代码,就能完全取代 Xposed API 实现同样的功能
代码量少,逻辑清晰,借助高效强大的 `YukiHookAPI`,你就可以实现一个非常简单的 Xposed 模块。 现在,借助高效强大的 `YukiHookAPI`,你就可以实现一个非常简单的 Xposed 模块。
## 支持的 Hook 框架 ## 支持的 Hook 框架
@@ -131,7 +191,7 @@ class MainHook : IXposedHookLoadPackage {
| Hook Framework | ST | Describe | | Hook Framework | ST | Describe |
| --------------------------------------------------------- | --- | ----------------------------------------------------------------------------------------- | | --------------------------------------------------------- | --- | ----------------------------------------------------------------------------------------- |
| [LSPosed](https://github.com/LSPosed/LSPosed) | ✅ | 多场景下稳定使用 | | [LSPosed](https://github.com/LSPosed/LSPosed) | ✅ | 多场景下稳定使用 |
| [EdXposed](https://github.com/ElderDrivers/EdXposed) | | 部分兼容 | | [EdXposed](https://github.com/ElderDrivers/EdXposed) | | 已停止维护,不再推荐使用 |
| [Pine](https://github.com/canyie/pine) | ⭕ | 可以使用 | | [Pine](https://github.com/canyie/pine) | ⭕ | 可以使用 |
| [SandHook](https://github.com/asLody/SandHook) | ⭕ | 可以使用 | | [SandHook](https://github.com/asLody/SandHook) | ⭕ | 可以使用 |
| [Whale](https://github.com/asLody/whale) | ⭕ | 需要 [xposed-hook-based-on-whale](https://github.com/WindySha/xposed-hook-based-on-whale) | | [Whale](https://github.com/asLody/whale) | ⭕ | 需要 [xposed-hook-based-on-whale](https://github.com/WindySha/xposed-hook-based-on-whale) |

View File

@@ -22,8 +22,10 @@ override fun onHook() = encase {
appInfo appInfo
// 得到宿主 Application 生命周期 // 得到宿主 Application 生命周期
appContext appContext
// 创建 Hook // Hook 指定的 APP
findClass("com.demo.Test").hook { loadApp(name = "com.demo.test") {
// Class Hook
findClass("com.demo.test.TestClass").hook {
injectMember { injectMember {
method { method {
name = "test" name = "test"
@@ -34,12 +36,29 @@ override fun onHook() = encase {
} }
} }
} }
// Resources Hook (固定用法)
resources().hook {
injectResource {
conditions {
name = "ic_launcher"
mipmap()
}
replaceToModuleResource(R.mipmap.ic_launcher)
}
}
}
} }
``` ```
#### **Xposed API** #### **Xposed API**
```kotlin ```kotlin
private lateinit var moduleResources: XModuleResources
override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam) {
moduleResources = XModuleResources.createInstance(sparam.modulePath, null)
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
// 得到当前 Hook 的包名 // 得到当前 Hook 的包名
lpparam.packageName lpparam.packageName
@@ -47,13 +66,21 @@ override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
lpparam.applicationInfo lpparam.applicationInfo
// 得到宿主 Application 生命周期 // 得到宿主 Application 生命周期
AndroidAppHelper.currentApplication() AndroidAppHelper.currentApplication()
// 创建 Hook // Class Hook
XposedHelpers.findAndHookMethod("com.demo.Test", lpparam.classLoader, "test", Boolean::class.java, object : XC_MethodHook() { if(lpparam.packageName == "com.demo.test")
XposedHelpers.findAndHookMethod("com.demo.test.TestClass", lpparam.classLoader, "test", Boolean::class.java, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) { override fun afterHookedMethod(param: MethodHookParam) {
// ... // ...
} }
}) })
} }
override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam) {
// 得到当前 Hook 的包名
resparam.packageName
// 创建 Hook
resparam.res.setReplacement("com.demo.test", "mipmap", "ic_launcher", moduleResources.fwd(R.mipmap.ic_launcher))
}
``` ```
<!-- tabs:end --> <!-- tabs:end -->

View File

@@ -101,7 +101,7 @@ dependencies {
```kotlin ```kotlin
@InjectYukiHookWithXposed @InjectYukiHookWithXposed
class MainHook : IYukiHookXposedInit { class HookEntry : IYukiHookXposedInit {
override fun onHook() = YukiHookAPI.encase { override fun onHook() = YukiHookAPI.encase {
// Your code here. // Your code here.
@@ -153,4 +153,4 @@ override fun attachBaseContext(base: Context?) {
### 特别说明 ### 特别说明
!> 由于你使用了自定义的 Hook 框架而并非模块,~~`YukiHookModuleStatus`~~ ~~`YukiHookModulePrefs`~~ 功能将失效。 !> 由于你使用了自定义的 Hook 框架而并非模块,~~`YukiHookModuleStatus`~~ ~~`YukiHookModulePrefs`~~ 以及 Resources Hook 功能将失效。

View File

@@ -11,7 +11,26 @@
```java ```java
package com.demo; package com.demo;
public class Test { public class BaseTest {
public BaseTest() {
// ...
}
public BaseTest(boolean isInit) {
// ...
}
private void doBaseTask(String taskName) {
// ...
}
}
```
```java
package com.demo;
public class Test extends BaseTest {
public Test() { public Test() {
// ... // ...
@@ -61,7 +80,7 @@ public class Test {
### 查询与反射调用 ### 查询与反射调用
假设我们要得到 `doTask` 方法并执行,通常情况下,我们可以使用标准的反射 API 去查询这个方法。 假设我们要得到 `Test`(以下统称“当前 `Class`”)的 `doTask` 方法并执行,通常情况下,我们可以使用标准的反射 API 去查询这个方法。
> 示例如下 > 示例如下
@@ -178,6 +197,54 @@ Test::class.java.method {
}.get(instance) // 得到这个方法 }.get(instance) // 得到这个方法
``` ```
### 在父类查询
你会注意到 `Test` 继承于 `BaseTest`,现在我们想得到 `BaseTest``doBaseTask` 方法,在不知道父类名称的情况下,要怎么做呢?
参照上面的查询条件,我们只需要在查询条件中加入一个 `superClass` 即可实现这个功能。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name = "doBaseTask"
param(StringType)
// 只需要添加这个条件
superClass()
}.get(instance).call("task_name")
```
这个时候我们就可以在父类中取到这个方法了。
`superClass` 有一个参数为 `isOnlySuperClass`,设置为 `true` 后,可以跳过当前 `Class` 仅查询当前 `Class` 的父类。
由于我们现在已知 `doBaseTask` 方法只存在于父类,可以加上这个条件节省查询时间。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name = "doBaseTask"
param(StringType)
// 加入一个查询条件
superClass(isOnlySuperClass = true)
}.get(instance).call("task_name")
```
这个时候我们同样可以得到父类中的这个方法。
`superClass` 一旦设置就会自动循环向后查找全部继承的父类中是否有这个方法,直到查询到目标没有父类(继承关系为 `java.lang.Object`)为止。
更多用法可参考 [superClass 方法](api/document?id=superclass-method)。
!> 当前查询的 `Method` 除非指定 `superClass` 条件,否则只能查询到当前 `Class``Method`
### 静态字节码 ### 静态字节码
有些方法和变量在 `Class` 中是静态的实现,这个时候,我们不需要传入实例就可以调用它们。 有些方法和变量在 `Class` 中是静态的实现,这个时候,我们不需要传入实例就可以调用它们。
@@ -347,6 +414,23 @@ instance.current {
} }
``` ```
我们还可以用 `superClass` 调用当前 `Class` 父类的方法。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 假设这个 Class 是不能被直接得到的
instance.current {
// 执行父类的 doBaseTask 方法
superClass().method {
name = "doBaseTask"
param(StringType)
}.call("task_name")
}
```
问题又来了,我想使用反射的方式创建如下的实例并调用其中的方法,该怎么做呢? 问题又来了,我想使用反射的方式创建如下的实例并调用其中的方法,该怎么做呢?
> 示例如下 > 示例如下
@@ -768,9 +852,9 @@ loggerE(msg = "This is an error")
```kotlin ```kotlin
// 假设这就是被抛出的异常 // 假设这就是被抛出的异常
val e = Throwable(...) val throwable = Throwable(...)
// 打印日志 // 打印日志
loggerE(msg = "This is an error", e = e) loggerE(msg = "This is an error", e = throwable)
``` ```
打印的结果为如下所示。 打印的结果为如下所示。

View File

@@ -44,7 +44,7 @@
coverpage: true, coverpage: true,
loadNavbar: true, loadNavbar: true,
loadSidebar: true, loadSidebar: true,
subMaxLevel: 3, subMaxLevel: 4,
auto2top: true, auto2top: true,
mergeNavbar: false, mergeNavbar: false,
notFoundPage: '_404.md', notFoundPage: '_404.md',
@@ -60,7 +60,7 @@
], ],
placeholder: '搜索文档', placeholder: '搜索文档',
noData: '噫,什么都没找到~', noData: '噫,什么都没找到~',
depth: 5, depth: 7,
hideOtherSidebarContent: true hideOtherSidebarContent: true
}, },
tabs: { tabs: {

View File

@@ -31,13 +31,16 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
/** /**
* 代码文件注入 * 代码文件注入模板类
*/ */
object CodeSourceFileTemplate { object CodeSourceFileTemplate {
/** 定义 Jvm 方法名 */ /** 定义 Jvm 方法名 */
private const val IS_ACTIVE_METHOD_NAME = "__--" private const val IS_ACTIVE_METHOD_NAME = "__--"
/** 定义 Jvm 方法名 */
private const val HAS_RESOURCES_HOOK_METHOD_NAME = "_--_"
/** 定义 Jvm 方法名 */ /** 定义 Jvm 方法名 */
private const val GET_XPOSED_VERSION_METHOD_NAME = "--__" private const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
@@ -92,80 +95,150 @@ object CodeSourceFileTemplate {
/** /**
* 获得 xposed_init 注入文件 * 获得 xposed_init 注入文件
* @param packageName 包名 * @param packageName 包名
* @param modulePackageName 模块包名
* @param entryClassName 入口类名 * @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名 * @param xInitClassName xposed_init 入口类名
* @return [ByteArray] * @return [ByteArray]
*/ */
fun getXposedInitFileByteArray(packageName: String, modulePackageName: String, entryClassName: String, xInitClassName: String) = fun getXposedInitFileByteArray(packageName: String, entryClassName: String, xInitClassName: String) =
("package $packageName\n" + ("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package $packageName\n" +
"\n" + "\n" +
"import androidx.annotation.Keep\n" + "import androidx.annotation.Keep\n" +
"import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookXposedBridge\n" + "import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" +
"import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus\n" +
"import com.highcapable.yukihookapi.hook.log.loggerE\n" +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" +
"import de.robv.android.xposed.XC_MethodReplacement\n" +
"import de.robv.android.xposed.XposedHelpers\n" +
"import de.robv.android.xposed.XposedBridge\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import $packageName.$entryClassName\n" + "import de.robv.android.xposed.IXposedHookInitPackageResources\n" +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" +
"import de.robv.android.xposed.IXposedHookZygoteInit\n" +
"import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"\n" + "\n" +
getCommentContent(entryClassName, currrentClassTag = "Xposed Init") + getCommentContent(entryClassName, currrentClassTag = "Xposed Init") +
"@Keep\n" + "@Keep\n" +
"@YukiGenerateApi\n" + "@YukiGenerateApi\n" +
"class $xInitClassName : IXposedHookLoadPackage {\n" + "class $xInitClassName : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources {\n" +
"\n" +
" override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" +
" ${entryClassName}_Impl.callInitZygote(sparam)\n" +
" YukiXposedEvent.EventHandler.callInitZygote(sparam)\n" +
" }\n" +
"\n" + "\n" +
" override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + " override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" if (lpparam == null) return\n" + " ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" +
" try {\n" + " YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" +
" $entryClassName().apply {\n" + " }\n" +
" onInit()\n" + "\n" +
" if (YukiHookXposedBridge.isXposedCallbackSetUp) {\n" + " override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"You cannot loading a hooker in \\\"onInit\\\" method! Aborted\")\n" + " ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" +
" YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" +
" }\n" +
"}").toByteArray()
/**
* 获得 xposed_init_Impl 注入文件
* @param packageName 包名
* @param modulePackageName 模块包名
* @param entryClassName 入口类名
* @return [ByteArray]
*/
fun getXposedInitImplFileByteArray(packageName: String, modulePackageName: String, entryClassName: String) =
("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package $packageName\n" +
"\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import com.highcapable.yukihookapi.hook.log.loggerE\n" +
"import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus\n" +
"import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge\n" +
"import de.robv.android.xposed.IXposedHookZygoteInit\n" +
"import de.robv.android.xposed.XC_MethodReplacement\n" +
"import de.robv.android.xposed.XposedHelpers\n" +
"import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"\n" +
getCommentContent(entryClassName, currrentClassTag = "Xposed Init Impl") +
"@YukiGenerateApi\n" +
"object ${entryClassName}_Impl {\n" +
"\n" +
" private const val modulePackageName = \"$modulePackageName\"\n" +
" private val hookEntry = $entryClassName()\n" +
" private var isZygoteBinded = false\n" +
" private var lpparam: XC_LoadPackage.LoadPackageParam? = null\n" +
"\n" +
" private fun callXposedLoaded(\n" +
" isZygoteLoaded: Boolean = false,\n" +
" lpparam: XC_LoadPackage.LoadPackageParam? = null,\n" +
" resparam: XC_InitPackageResources.InitPackageResourcesParam? = null\n" +
" ) {\n" +
" if (isZygoteBinded.not()) runCatching {\n" +
" hookEntry.onXposedEvent()\n" +
" hookEntry.onInit()\n" +
" if (YukiHookBridge.isXposedCallbackSetUp) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"You cannot load a hooker in \\\"onInit\\\" or \\\"onXposedEvent\\\" method! Aborted\")\n" +
" return\n" + " return\n" +
" }\n" + " }\n" +
" onHook()\n" + " hookEntry.onHook()\n" +
" YukiHookBridge.callXposedInitialized()\n" +
" YukiHookBridge.modulePackageName = modulePackageName\n" +
" }.onFailure { loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = it) }\n" +
" YukiHookBridge.callXposedLoaded(isZygoteLoaded, lpparam, resparam)\n" +
" }\n" + " }\n" +
" YukiHookXposedBridge.callXposedInitialized()\n" + "\n" +
" } catch (e: Throwable) {\n" + " private fun hookModuleAppStatus(lpparam: XC_LoadPackage.LoadPackageParam? = this.lpparam, isHookResourcesStatus: Boolean = false) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = e)\n" + " lpparam?.let { this.lpparam = it }\n" +
" }\n" + " if (isHookResourcesStatus.not()) {\n" +
" if (lpparam.packageName == \"$modulePackageName\") {\n" +
" XposedHelpers.findAndHookMethod(\n" + " XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" + " YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" + " this.lpparam?.classLoader,\n" +
" \"$IS_ACTIVE_METHOD_NAME\",\n" + " \"$IS_ACTIVE_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" + " object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = true\n" + " override fun replaceHookedMethod(param: MethodHookParam?) = true\n" +
" })\n" + " })\n" +
" XposedHelpers.findAndHookMethod(\n" + " XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" + " YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" + " this.lpparam?.classLoader,\n" +
" \"$GET_XPOSED_TAG_METHOD_NAME\",\n" + " \"$GET_XPOSED_TAG_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" + " object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" + " override fun replaceHookedMethod(param: MethodHookParam?) = YukiHookBridge.executorName\n" +
" XposedBridge::class.java.getDeclaredField(\"TAG\").apply { isAccessible = true }.get(null) as String\n" +
" } catch (_: Throwable) {\n" +
" \"invalid\"\n" +
" }\n" +
" })\n" + " })\n" +
" XposedHelpers.findAndHookMethod(\n" + " XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" + " YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" + " this.lpparam?.classLoader,\n" +
" \"$GET_XPOSED_VERSION_METHOD_NAME\",\n" + " \"$GET_XPOSED_VERSION_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" + " object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" + " override fun replaceHookedMethod(param: MethodHookParam?) = YukiHookBridge.executorVersion\n" +
" XposedBridge.getXposedVersion()\n" + " })\n" +
" } catch (_: Throwable) {\n" + " } else XposedHelpers.findAndHookMethod(\n" +
" -1\n" + " YukiHookModuleStatus::class.java.name,\n" +
" }\n" + " this.lpparam?.classLoader,\n" +
" \"$HAS_RESOURCES_HOOK_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = true\n" +
" })\n" + " })\n" +
" YukiHookXposedBridge.isModulePackageXposedEnv = true\n" +
" }\n" + " }\n" +
" YukiHookXposedBridge.modulePackageName = \"$modulePackageName\"\n" + "\n" +
" YukiHookXposedBridge.callXposedLoaded(lpparam)\n" + " @YukiGenerateApi\n" +
" fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" +
" if (sparam == null) return\n" +
" runCatching {\n" +
" YukiHookBridge.callXposedZygoteLoaded(sparam)\n" +
" }.onFailure { loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI bind initZygote failed\", e = it) }\n" +
" callXposedLoaded(isZygoteLoaded = true)\n" +
" isZygoteBinded = true\n" +
" }\n" +
"\n" +
" @YukiGenerateApi\n" +
" fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" if (lpparam == null) return\n" +
" if (lpparam.packageName == modulePackageName) hookModuleAppStatus(lpparam)\n" +
" callXposedLoaded(lpparam = lpparam)\n" +
" }\n" +
"\n" +
" @YukiGenerateApi\n" +
" fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" +
" if (resparam == null) return\n" +
" if (resparam.packageName == modulePackageName) hookModuleAppStatus(isHookResourcesStatus = true)\n" +
" callXposedLoaded(resparam = resparam)\n" +
" }\n" + " }\n" +
"}").toByteArray() "}").toByteArray()
} }