Skip to content

Commit cf213ad

Browse files
author
zhangzhengtian02
committedJan 26, 2024
update README
1 parent dd64e36 commit cf213ad

File tree

2 files changed

+284
-2
lines changed

2 files changed

+284
-2
lines changed
 

‎README.md

+142-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,147 @@ Kotlin IR Dissector(K.I.D)是一个用于编译期 transform Kotlin IR 的工具
88

99
## 安装
1010

11+
settings.gradle 中添加仓库源
12+
```kotlin
13+
pluginManagement {
14+
repositories {
15+
gradlePluginPortal()
16+
mavenCentral()
17+
}
18+
}
19+
```
20+
21+
工程中依赖插件
22+
```kotlin
23+
plugins {
24+
id("io.github.androidzzt.kid-plugin") version <latest_version>
25+
}
26+
```
27+
28+
KMP(Kotlin Multiplatform) 工程中依赖注解库
29+
```kotlin
30+
kotlin {
31+
sourceSets {
32+
val commonMain by getting {
33+
dependencies {
34+
implementation("io.github.androidzzt.kid:kid-annotation:<latest_version>")
35+
}
36+
}
37+
}
38+
}
39+
```
40+
41+
Kotlin Android(JVM) 工程中依赖注解库
42+
```kotlin
43+
dependencies {
44+
implementation("io.github.androidzzt.kid:kid-annotation:<latest_version>")
45+
}
46+
```
47+
1148
## 功能
1249

13-
## 示例
50+
### 1. Hook 目标方法入口
51+
52+
```kotlin
53+
@Target(AnnotationTarget.FUNCTION)
54+
@Retention(AnnotationRetention.SOURCE)
55+
annotation class EntryHook(
56+
val className: String, // 目标方法所在类的全限定名
57+
val methodName: String, // 目标方法名
58+
val paramsTypes: String, // 目标方法参数类型列表,以逗号分隔
59+
val ignoreSuper: Boolean = false // 是否忽略调用 super
60+
)
61+
```
62+
63+
比如,现在有 `com.example.Logger#log` 方法,定义如下:
64+
```kotlin
65+
package com.example
66+
67+
class Logger {
68+
val tag = "Logger"
69+
fun log(msg: String) {
70+
println(msg)
71+
}
72+
}
73+
```
74+
我们想要 hook log 方法的入口,可以这样写:
75+
```kotlin
76+
import com.example.Logger
77+
import com.zzt.kid.annotation.EntryHook
78+
import com.zzt.kid.runtime.MethodHook
79+
80+
object LoggerEntryHook {
81+
@EntryHook(
82+
className = "com.example.Logger",
83+
methodName = "log",
84+
paramsTypes = "(kotlin.String)" // 注意,这里的参数类型需要加上括号,如果有多个参数,以逗号分隔
85+
)
86+
fun hookLogEntry(caller: Logger, msg: String): MethodHook<Unit> {
87+
println("entry: ${caller.tag}:: msg=$msg")
88+
return MethodHook.intercept() // 返回 MethodHook.intercept() 表示拦截目标方法,不再执行
89+
}
90+
}
91+
```
92+
93+
上面代码中有一个类 `MethodHook`, 定义如下:
94+
```kotlin
95+
class MethodHook<T>(val ret: T? = null) {
96+
var pass: Boolean = ret == null
97+
98+
companion object {
99+
fun <T> pass() = MethodHook<T>(null).apply { pass = true }
100+
fun <T> intercept(ret: T? = null) = MethodHook(ret)
101+
}
102+
}
103+
```
104+
- 泛型 T 是目标方法的返回类型,如果目标方法无返回类型,那么 T 就是 Unit
105+
- `MethodHook.pass()` 表示继续执行目标方法
106+
- `MethodHook.intercept()` 表示拦截目标方法,不再执行,如果目标方法有返回值,可以通过 `MethodHook.intercept(ret)` 来指定返回值
107+
108+
经过 LogEntryHook 的处理后,Logger#log 方法的实现变成了这样:
109+
```kotlin
110+
package com.example
111+
112+
class Logger {
113+
val tag = "Logger"
114+
fun log(msg: String) {
115+
val methodHook = LoggerEntryHook.hookLogEntry(this, msg)
116+
if (methodHook.pass) {
117+
println(msg)
118+
}
119+
}
120+
}
121+
```
122+
123+
### 2. 完全替换目标方法
124+
125+
```kotlin
126+
@Target(AnnotationTarget.FUNCTION)
127+
@Retention(AnnotationRetention.SOURCE)
128+
annotation class Replace(
129+
val className: String, // 目标方法所在类的全限定名
130+
val methodName: String, // 目标方法名
131+
val paramsTypes: String, // 目标方法参数类型列表,以逗号分隔
132+
val ignoreSuper: Boolean = false // 是否忽略调用 super
133+
)
134+
```
135+
136+
比如,我们认为 log 方法内部可能出现异常,我们想替换 log 方法,让它在出现异常时打印异常信息,可以这样写:
137+
```kotlin
138+
object LoggerHook {
139+
@Replace(
140+
className = "com.example.Logger",
141+
methodName = "log",
142+
paramsTypes = "(kotlin.String)"
143+
)
144+
fun replaceLog(caller: Logger, msg: String) {
145+
try {
146+
println(msg)
147+
} catch (e: Exception) {
148+
e.printStackTrace()
149+
}
150+
}
151+
}
152+
```
153+
注意,@Replace 不需要配合 MethodHook 使用,插件会将目标方法的实现完全替换成注解方法的实现。
154+

‎README_EN.md

+142-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,147 @@ Kotlin IR Dissector(K.I.D) is a tool for transforming Kotlin IR at compile time.
77

88
## Installation
99

10+
add repositories in settings.gradle
11+
```kotlin
12+
pluginManagement {
13+
repositories {
14+
gradlePluginPortal()
15+
mavenCentral()
16+
}
17+
}
18+
```
19+
20+
add plugin in project
21+
```kotlin
22+
plugins {
23+
id("io.github.androidzzt.kid-plugin") version <latest_version>
24+
}
25+
```
26+
27+
add anno dependencies in KMP(Kotlin Multiplatform) project
28+
```kotlin
29+
kotlin {
30+
sourceSets {
31+
val commonMain by getting {
32+
dependencies {
33+
implementation("io.github.androidzzt.kid:kid-annotation:<latest_version>")
34+
}
35+
}
36+
}
37+
}
38+
```
39+
40+
add anno dependencies in Android(JVM) project
41+
```kotlin
42+
dependencies {
43+
implementation("io.github.androidzzt.kid:kid-annotation:<latest_version>")
44+
}
45+
```
46+
1047
## Features
1148

12-
## Sample
49+
### 1. Hook target method entry
50+
51+
```kotlin
52+
@Target(AnnotationTarget.FUNCTION)
53+
@Retention(AnnotationRetention.SOURCE)
54+
annotation class EntryHook(
55+
val className: String, // target method class name
56+
val methodName: String, // target method name
57+
val paramsTypes: String, // target method params types, separated by commas
58+
val ignoreSuper: Boolean = false // ignore super call
59+
)
60+
```
61+
62+
for example, there is a method `com.example.Logger#log`:
63+
```kotlin
64+
package com.example
65+
66+
class Logger {
67+
val tag = "Logger"
68+
fun log(msg: String) {
69+
println(msg)
70+
}
71+
}
72+
```
73+
74+
we want to hook the entry of log method, we can write like this:
75+
```kotlin
76+
import com.example.Logger
77+
import com.zzt.kid.annotation.EntryHook
78+
import com.zzt.kid.runtime.MethodHook
79+
80+
object LoggerEntryHook {
81+
@EntryHook(
82+
className = "com.example.Logger",
83+
methodName = "log",
84+
paramsTypes = "(kotlin.String)" // 注意,这里的参数类型需要加上括号,如果有多个参数,以逗号分隔
85+
)
86+
fun hookLogEntry(caller: Logger, msg: String): MethodHook<Unit> {
87+
println("entry: ${caller.tag}:: msg=$msg")
88+
return MethodHook.intercept() // 返回 MethodHook.intercept() 表示拦截目标方法,不再执行
89+
}
90+
}
91+
```
92+
93+
the `MethodHook` class is defined as follows:
94+
```kotlin
95+
class MethodHook<T>(val ret: T? = null) {
96+
var pass: Boolean = ret == null
97+
98+
companion object {
99+
fun <T> pass() = MethodHook<T>(null).apply { pass = true }
100+
fun <T> intercept(ret: T? = null) = MethodHook(ret)
101+
}
102+
}
103+
```
104+
- generic T is the return type of the target method, if the target method has no return type, then T is Unit
105+
- `MethodHook.pass()` means continue to execute the target method
106+
- `MethodHook.intercept()` means intercept the target method, if the target method has a return value, you can specify the return value through `MethodHook.intercept(ret)`
107+
108+
after the above code is compiled, the implementation of Logger#log method will become like this:
109+
```kotlin
110+
package com.example
111+
112+
class Logger {
113+
val tag = "Logger"
114+
fun log(msg: String) {
115+
val methodHook = LoggerEntryHook.hookLogEntry(this, msg)
116+
if (methodHook.pass) {
117+
println(msg)
118+
}
119+
}
120+
}
121+
```
122+
123+
### 2. Replace target method completely
124+
125+
```kotlin
126+
@Target(AnnotationTarget.FUNCTION)
127+
@Retention(AnnotationRetention.SOURCE)
128+
annotation class Replace(
129+
val className: String, // 目标方法所在类的全限定名
130+
val methodName: String, // 目标方法名
131+
val paramsTypes: String, // 目标方法参数类型列表,以逗号分隔
132+
val ignoreSuper: Boolean = false // 是否忽略调用 super
133+
)
134+
```
135+
136+
for example, we think that an exception may occur in the log method, and we want to replace the log method to print the exception information when an exception occurs. We can write like this:
137+
```kotlin
138+
object LoggerHook {
139+
@Replace(
140+
className = "com.example.Logger",
141+
methodName = "log",
142+
paramsTypes = "(kotlin.String)"
143+
)
144+
fun replaceLog(caller: Logger, msg: String) {
145+
try {
146+
println(msg)
147+
} catch (e: Exception) {
148+
e.printStackTrace()
149+
}
150+
}
151+
}
152+
```
153+
Be careful, @Replace does not need to be used with MethodHook. The plugin will completely replace the implementation of the target method with the implementation of the annotation method.

0 commit comments

Comments
 (0)
Please sign in to comment.