mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 17:55:24 +08:00
366 lines
9.6 KiB
Markdown
366 lines
9.6 KiB
Markdown
# API 基本配置
|
||
|
||
> 这里介绍了 `YukiHookAPI` 的基本配置方法。
|
||
|
||
## 功能配置
|
||
|
||
> 无论是 [作为 Xposed 模块使用](config/xposed-using) 还是 [作为 Hook API 使用](config/api-using),你都可以在 API 装载之前或装载过程中对 `YukiHookAPI` 进行配置。
|
||
|
||
### configs 方法
|
||
|
||
```kotlin
|
||
fun configs(initiate: Configs.() -> Unit)
|
||
```
|
||
|
||
`configs` 方法对 `Configs` 类实现了一个 `lambda` 方法体,你可以轻松地调用它进行配置。
|
||
|
||
你可以 [点击这里](api/document?id=configs-method) 查看有关用法的说明和示例。
|
||
|
||
## Hooker 配置
|
||
|
||
> 一个 Xposed 模块或 Hook API 最重要的地方就是 Hooker 的创建与使用,`YukiHookAPI` 提供了两种使用方法。
|
||
|
||
### 通过 lambda 创建
|
||
|
||
> 这种方案是最简单的,如果你的模块功能不多,代码数量不大,不需要进行分类处理,推荐使用这种方式进行创建。
|
||
|
||
#### encase 方法
|
||
|
||
```kotlin
|
||
fun encase(initiate: PackageParam.() -> Unit)
|
||
```
|
||
|
||
`encase` 方法是 Hook 一切生命的开始,在一个模块或一个 Hook 过程中,`encase` 方法只能作用一次,用于创建 Hooker。
|
||
|
||
`PackageParam` 为宿主(目标 APP)的重要实例对象,通过 `PackageParam` 来实现对当前 Hook 作用对象的全部 Hook 操作。
|
||
|
||
你可以 [点击这里](api/document?id=packageparam-class) 了解其中的详细用法。
|
||
|
||
`encase` 方法可以在 `onHook` 方法中使用两种方案创建。
|
||
|
||
> 示例代码 1
|
||
|
||
```kotlin
|
||
YukiHookAPI.encase {
|
||
loadApp(name = "com.example.demo") {
|
||
findClass(name = "$packageName.DemoClass").hook {
|
||
// Your code here.
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> 示例代码 2
|
||
|
||
```kotlin
|
||
encase {
|
||
loadApp(name = "com.example.demo") {
|
||
findClass(name = "$packageName.DemoClass").hook {
|
||
// Your code here.
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
在 `encase` 方法中进行你的 Hook 操作。
|
||
|
||
### 通过自定义 Hooker 创建
|
||
|
||
> 这种方案更加适用于大型项目,例如需要对 Hooker 进行分类或对 Hook 的作用对象进行分类。
|
||
|
||
#### encase 方法
|
||
|
||
```kotlin
|
||
fun encase(vararg hooker: YukiBaseHooker)
|
||
```
|
||
|
||
同样为 `encase` 方法,这里的方法可变数组参数 `hooker` 为创建入口提供了一个对象,你可以将所有继承于 `YukiBaseHooker` 的 Hooker 一次性进行装载。
|
||
|
||
#### YukiBaseHooker 用法
|
||
|
||
`YukiBaseHooker` 继承于 `PackageParam`,你需要将你的子 Hooker 继承于 `YukiBaseHooker`。
|
||
|
||
若要了解更多可 [点击这里](api/document?id=yukibasehooker-class) 进行查看。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
object CustomHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
// Your code here.
|
||
}
|
||
}
|
||
```
|
||
|
||
子 Hooker **建议使用**单例 `object` 创建,你也可以使用 `class` 但不推荐。
|
||
|
||
!> 你无需再在继承于 `YukiBaseHooker` 的 `onHook` 方法中重新调用 `encase`,这是错误的,你应该直接开始编写你的 Hook 代码。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
object CustomHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
loadApp(name = "com.example.demo1") {
|
||
findClass(name = "$packageName.DemoClass").hook {
|
||
// Your code here.
|
||
}
|
||
}
|
||
loadApp(name = "com.example.demo2") {
|
||
findClass(name = "$packageName.CustomClass").hook {
|
||
// Your code here.
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
作为子 Hooker 使用,你还可以在外部调用 `loadApp` 方法,然后在内部直接开始 Hook。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
class HookEntry : IYukiHookXposedInit {
|
||
|
||
override fun onHook() = encase {
|
||
loadApp(name = "com.example.demo", ChildCustomHooker)
|
||
}
|
||
}
|
||
|
||
object ChildCustomHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
findClass(name = "$packageName.DemoClass").hook {
|
||
// Your code here.
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
你可以使用 `loadHooker` 方法在子 Hooker 中多层装载另一个 Hooker,请按照你的喜好进行即可。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
object FirstHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
findClass(name = "$packageName.DemoClass").hook {
|
||
// Your code here.
|
||
}
|
||
loadHooker(SecondHooker)
|
||
loadHooker(ThirdHooker)
|
||
}
|
||
}
|
||
```
|
||
|
||
搭建完全部 Hooker 后,你就可以在你的 `HookEntryClass` 入口类中的 `onHook` 方法中装载你的 Hooker 了。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
class HookEntry : IYukiHookXposedInit {
|
||
|
||
override fun onHook() =
|
||
YukiHookAPI.encase(FirstHooker, SecondHooker, ThirdHooker ...)
|
||
}
|
||
```
|
||
|
||
当然,我们同样可以对其进行简写。
|
||
|
||
> 示例如下
|
||
|
||
```kotlin
|
||
class HookEntry : IYukiHookXposedInit {
|
||
|
||
override fun onHook() = encase(FirstHooker, SecondHooker, ThirdHooker ...)
|
||
}
|
||
```
|
||
|
||
### 扩展特性
|
||
|
||
如果你当前使用的 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` 方法来装载新的进程被 fork 后的第一个事件 `initZygote`。
|
||
|
||
> 示例如下
|
||
|
||
```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.
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 注意事项
|
||
|
||
!> 无论使用 `encase` 创建 `lambda` 方法体还是直接使用 Hooker 形式,你都不应该直接在首个 `onHook` 事件中直接装载 Hooker 或直接开始 Hook。
|
||
|
||
直接装载 Hooker 或直接开始 Hook 是错误的,`encase` 事件在被 Hook Framework 装载后,会经历三次回调。
|
||
|
||
- 装载 `initZygote` → `encase`
|
||
|
||
- 装载 `handleLoadPackage` → `encase`
|
||
|
||
- 装载 `handleInitPackageResources` → `encase`
|
||
|
||
在这个过程中,你需要使用 `loadApp`、`loadSystem`、`loadZygote` 来区分每一次装载代码的调用域,否则你的代码就会被<u>**多次执行造成错误**</u>。
|
||
|
||
下面是两个**错误**示例。
|
||
|
||
> 示例代码 1
|
||
|
||
```kotlin
|
||
encase {
|
||
// ❗错误的使用方法,不能直接装载 Hooker
|
||
loadHooker(CustomHooker)
|
||
// ❗错误的使用方法,不能直接开始 Hook
|
||
findClass(name = "com.example.demo.DemoClass").hook {
|
||
// ...
|
||
}
|
||
// ❗错误的使用方法,不能直接开始 Hook
|
||
resources().hook {
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
> 示例代码 2
|
||
|
||
```kotlin
|
||
class HookEntry : IYukiHookXposedInit {
|
||
|
||
override fun onHook() {
|
||
encase(CustomHooker)
|
||
}
|
||
}
|
||
|
||
object CustomHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
// ❗错误的使用方法,由于外层没有任何判断对象,不能直接开始 Hook
|
||
findClass(name = "com.example.demo.DemoClass").hook {
|
||
// ...
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
下面是上述错误示例的**正确**示例。
|
||
|
||
> 示例代码 1
|
||
|
||
```kotlin
|
||
encase {
|
||
// ✅ 正确的使用方法,在 Zygote 中装载
|
||
loadZygote(CustomHooker)
|
||
// ✅ 正确的使用方法,在 Zygote 中装载
|
||
loadZygote {
|
||
// ✅ 正确的使用方法,在 Zygote 内 Hook
|
||
resources().hook {
|
||
// ...
|
||
}
|
||
}
|
||
// ✅ 正确的使用方法,使用 APP 作用域装载
|
||
loadApp(/** name 参数可选 */, hooker = CustomHooker)
|
||
// ✅ 正确的使用方法,判断 APP 作用域后再装载 Hooker
|
||
loadApp(/** name 参数可选 */) {
|
||
loadHooker(CustomHooker)
|
||
// ✅ 正确的使用方法,在 APP 作用域内 Hook
|
||
findClass(name = "com.example.demo.DemoClass").hook {
|
||
// ...
|
||
}
|
||
// ✅ 正确的使用方法,在 APP 作用域内 Hook
|
||
resources().hook {
|
||
// ...
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> 示例代码 2
|
||
|
||
```kotlin
|
||
class HookEntry : IYukiHookXposedInit {
|
||
|
||
override fun onHook() {
|
||
encase(CustomHooker)
|
||
}
|
||
}
|
||
|
||
object CustomHooker : YukiBaseHooker() {
|
||
|
||
override fun onHook() {
|
||
// ✅ 正确的使用方法,由于外层没有任何判断对象,需要判断 APP 作用域后再进行 Hook
|
||
loadApp(/** name 参数可选 */) {
|
||
findClass(name = "com.example.demo.DemoClass").hook {
|
||
// ...
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 作为 Hook API 使用需要注意的地方
|
||
|
||
若你作为 Hook API 使用,那么你只需要在入口处对 `encase` 方法进行区分。
|
||
|
||
!> `encase` 方法对作为 Hook API 使用提供了两个完全一样的方法,但是比前两者仅多出一个参数 `baseContext`。
|
||
|
||
> 方法 1
|
||
|
||
```kotlin
|
||
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit)
|
||
```
|
||
> 方法 2
|
||
|
||
```kotlin
|
||
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
|
||
```
|
||
|
||
此处的 `baseContext` 只需填入你在 `attachBaseContext` 处得到的 `Context` 即可,其它用法与上述内容完全一致。
|
||
|
||
!> 切勿以 Xposed 方式使用 `encase` 方法而漏掉 `baseContext` 参数,否则你的 Hook 将完全不工作。
|
||
|
||
!> Resources Hook 功能不支持作为 Hook API 使用。
|
||
|
||
<br/><br/>
|
||
[浏览下一篇 ➡️](config/api-exception.md) |