mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-07 03:05:36 +08:00
Merge new documentation
This commit is contained in:
347
docs/guide/example.md
Normal file
347
docs/guide/example.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# 用法示例
|
||||
|
||||
> 这里介绍了 `YukiHookAPI` 的基本工作方式以及列举了简单的 Hook 例子和常用功能。
|
||||
|
||||
## 结构图解
|
||||
|
||||
> 下方的结构描述了 `YukiHookAPI` 的基本工作方式和原理。
|
||||
|
||||
```
|
||||
Host Environment
|
||||
└── YukiHookCreater
|
||||
└── Class
|
||||
└── MemberHookCreater
|
||||
└── Member
|
||||
├── Before
|
||||
└── After
|
||||
MemberHookCreater
|
||||
└── Member
|
||||
├── Before
|
||||
└── After
|
||||
...
|
||||
```
|
||||
|
||||
> 上方的结构换做代码将可写为如下形式。
|
||||
|
||||
```kotlin
|
||||
TargetClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
// Your code here.
|
||||
}
|
||||
beforeHook {
|
||||
// Your code here.
|
||||
}
|
||||
afterHook {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
> 你可以在下方找到 API 提供的 Demo 来学习 `YukiHookAPI` 的使用方法。
|
||||
|
||||
- 宿主 APP Demo [点击这里查看](https://github.com/fankes/YukiHookAPI/tree/master/demo-app)
|
||||
|
||||
- 模块 APP Demo [点击这里查看](https://github.com/fankes/YukiHookAPI/tree/master/demo-module)
|
||||
|
||||
同时安装宿主和模块 Demo,通过激活模块来测试宿主中被 Hook 的功能。
|
||||
|
||||
## 一个简单的 Hook 例子
|
||||
|
||||
假设,我们要 Hook `com.android.browser` 中的 `onCreate` 方法并弹出一个对话框。
|
||||
|
||||
在 `encase` 方法体中添加代码。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
loadApp(name = "com.android.browser") {
|
||||
ActivityClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onCreate"
|
||||
param(BundleClass)
|
||||
returnType = UnitType
|
||||
}
|
||||
afterHook {
|
||||
AlertDialog.Builder(instance())
|
||||
.setTitle("Hooked")
|
||||
.setMessage("I am hook!")
|
||||
.setPositiveButton("OK", null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
至此,`onCreate` 方法将被成功 Hook 并在 `com.android.browser` 中的每个 `Activity` 启动时弹出此对话框。
|
||||
|
||||
那么,我想继续 Hook `onStart` 方法要怎么做呢?
|
||||
|
||||
在刚刚的代码中,继续插入一个 `injectMember` 方法体即可。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
loadApp(name = "com.android.browser") {
|
||||
ActivityClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onCreate"
|
||||
param(BundleClass)
|
||||
returnType = UnitType
|
||||
}
|
||||
afterHook {
|
||||
AlertDialog.Builder(instance())
|
||||
.setTitle("Hooked")
|
||||
.setMessage("I am hook!")
|
||||
.setPositiveButton("OK", null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
injectMember {
|
||||
method {
|
||||
name = "onStart"
|
||||
returnType = UnitType
|
||||
}
|
||||
afterHook {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
对于当前项目下没有的 `Class`,你可以使用 `stub` 方式或 `findClass` 方法来得到需要 Hook 的类。
|
||||
|
||||
比如,我要得到 `com.example.demo.TestClass`。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
findClass(name = "com.example.demo.TestClass").hook {
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
若 `com.example.demo` 是你要 Hook 的 APP,那么写法可以更简单。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
findClass(name = "$packageName.TestClass").hook {
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
到这里有些同学可能就开始说了,在某些场景下 `findClass` 显得有些繁琐。
|
||||
|
||||
因为可能有些同学有如下需求。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
const val TestClass = "com.example.demo.TestClass"
|
||||
|
||||
TestClass.hook {
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
没关系,你还可以使用字符串类名直接创建一个 Hook。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
("$packageName.TestClass").hook {
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 异常处理
|
||||
|
||||
> `YukiHookAPI` 重新设计了对异常的监听,任何异常都不会在 Hook 过程中抛出,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。
|
||||
|
||||
你可以处理 Hook 方法过程发生的异常。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}.result {
|
||||
// 处理 Hook 开始时的异常
|
||||
onHookingFailure {}
|
||||
// 处理 Hook 过程中的异常
|
||||
onConductFailure { param, throwable -> }
|
||||
// 处理全部异常
|
||||
onAllFailure {}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
你还可以处理 Hook 的 `Class` 不存在时发生的异常。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
TargetClass.hook {
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}
|
||||
}.onHookClassNotFoundFailure {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
你还可以处理查找方法时的异常。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
method {
|
||||
// Your code here.
|
||||
}.onNoSuchMethod {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
这里介绍了可能发生的常见异常,若要了解更多请参考 [API 异常处理](config/api-exception.md)。
|
||||
|
||||
## 状态监听
|
||||
|
||||
在使用 `XposedHelper` 的同学往往会在 Hook 后打印 `UnHook` 的方法确定是否 Hook 成功。
|
||||
|
||||
在 `YukiHookAPI` 中,你可以用以下方法方便地重新实现这个功能。
|
||||
|
||||
首先我们可以监听 Hook 已经准备开始。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
YourClass.hook {
|
||||
// Your code here.
|
||||
}.onPrepareHook {
|
||||
loggerD(msg = "$instanceClass hook start")
|
||||
}
|
||||
```
|
||||
|
||||
!> 请注意 `instanceClass` 建议只在 `onPrepareHook` 中使用,万一被 Hook 的 `Class` 不存在将会抛出无法拦截的异常导致 Hook 进程“死掉”。
|
||||
|
||||
然后,我们还可以对 Hook 的方法结果进行监听是否成功。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
injectMember {
|
||||
// Your code here.
|
||||
}.onHooked { member ->
|
||||
loggerD(msg = "$member has hooked")
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展用法
|
||||
|
||||
> 你可以在 Hook 过程中使用下面的方法方便地实现各种判断和功能。
|
||||
|
||||
### 多个宿主
|
||||
|
||||
如果你的模块需要同时处理多个 APP 的 Hook 事件,你可以使用 `loadApp` 方法体来区分你要 Hook 的 APP。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
loadApp(name = "com.android.browser") {
|
||||
// Your code here.
|
||||
}
|
||||
loadApp(name = "com.android.phone") {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
详细用法可 [点击这里](api/document?id=loadapp-method) 进行查看。
|
||||
|
||||
### 多个进程
|
||||
|
||||
如果你 Hook 的宿主 APP 有多个进程,你可以使用 `withProcess` 方法体来对它们分别进行 Hook。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
withProcess(mainProcessName) {
|
||||
// Your code here.
|
||||
}
|
||||
withProcess(name = "$packageName:tool") {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
详细用法可 [点击这里](api/document?id=withprocess-method) 进行查看。
|
||||
|
||||
## 写法优化
|
||||
|
||||
为了使代码更加简洁,你可以删去 `YukiHookAPI` 的名称,将你的 `onHook` 入口写作 `lambda` 形式。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
override fun onHook() = encase {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
## Xposed 模块判断自身激活状态
|
||||
|
||||
通常情况下,我们会选择写一个方法,使其返回 `false`,然后 Hook 掉这个方法使其返回 `true` 来证明 Hook 已经生效。
|
||||
|
||||
在 `YukiHookAPI` 中你完全不需要再这么做了,`YukiHookAPI` 已经帮你封装好了这个操作,你可以直接进行使用。
|
||||
|
||||
现在,你可以直接使用 `isXposedModuleActive` 在模块中判断自身是否被激活。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
if(isXposedModuleActive) {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
由于一些特殊原因,在太极、无极中的模块无法使用标准方法检测激活状态。
|
||||
|
||||
此时你可以在 `Activity` 中使用 `isTaiChiModuleActive` 判断自身是否被激活。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
if(isTaiChiModuleActive) {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
若你想使用两者得兼的判断方案,`YukiHookAPI` 同样为你封装了便捷的方式。
|
||||
|
||||
此时你可以在 `Activity` 中使用 `isModuleActive` 判断自身是否在 Xposed 或太极、无极中被激活。
|
||||
|
||||
> 示例如下
|
||||
|
||||
```kotlin
|
||||
if(isModuleActive) {
|
||||
// Your code here.
|
||||
}
|
||||
```
|
||||
|
||||
若要了解更多可 [点击这里](api/document?id=ismoduleactive-field) 进行查看。
|
||||
|
||||
!> 除了提供标准 API 的 Hook 框架之外,其它情况下模块可能都将无法判断自己是否被激活。
|
Reference in New Issue
Block a user