第一个 ClassTransformer
创建工程
在写第一个 ClassTransformer 之前,需要有一个 Java 或 Kotlin 工程,这里有两种工程形式。
buildSrc 工程
如果已经有一个 Android 工程了,可以直接在工程根目录新建一个 buildSrc 目录,Gradle 会把 buildSrc 当作构建工程,对它进行编译和测试,然后将其加入 buildscript 的 classpath 中,对于有多个子程的项目来说,只能有一个 buildSrc 目录位于工程根目录,对于复杂的构建来说,优先选择通过 buildSrc 来组织构建脚本。
然后在 buildSrc 目录下,创建如下目录结构:
buildSrc/
├── build.gradle
└── src
└── main
├── java
└── kotlin
2
3
4
5
6
对于 Android 开发者来说,推荐用 buildSrc 的方式,这样在一个工程中,上手更容易。
独立的 Java 工程
如果需要将 ClassTransformer 共享给多个 Android 工程,采用独立的 Java 工程会更合适。
我们可以通过 gradle 命令,来创建一个 Java 工程:
$ mkdir BoosterDemo # 创建 BoosterDemo 工程
$ cd BoosterDemo && gradle init # 初始化工程
2
然后选择工程类型:
Starting a Gradle Daemon (subsequent builds will be faster)
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4]
2
3
4
5
6
7
8
这里,我们选择 3: library,接下来,选择语言:
Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6]
2
3
4
5
6
7
8
这里可以根据自己的喜好选择: Groovy / Java / Kotlin / Scala 其中之一,假设,我们选择 4: Kotlin:
接下来,选择构建脚本的 DSL:
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Kotlin) [1..2]
2
3
4
如果对 Kotlin DSL 不太熟的话,可以选择 1: Groovy:
然后,输入工程名,或者用默认的工程名(目录名):
Project name (default: BoosterDemo):
然后输入源代码的包名:
Source package (default: BoosterDemo): io.johnsonlee.booster.demo
这样,Java Library 工程就创建好了。
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── kotlin
│ │ └── io
│ │ └── johnsonlee
│ │ └── booster
│ │ └── Library.kt
│ └── resources
└── test
├── kotlin
│ └── io
│ └── johnsonlee
│ └── booster
│ └── LibraryTest.kt
└── resources
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
提示
如果采用独立的 Java Library 工程需要将 Java Library 工程发布到 Maven 仓库才能集成到 Android 工程中,例如:发布到本地 Maven 仓库:
./gradlew publishToMavenLocal
引入 Booster
准备好工程后,接下来在 Java Library 工程或者 Android 工程的 buildSrc 目录中的 build.gradle 文件中,引入 Booster 依赖:
buildscript {
ext {
agp_version = "4.0.0"
booster_version = "4.16.3"
kotlin_version = "1.5.31"
}
repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
sourceSets {
main {
java {
srcDirs += []
}
kotlin {
srcDirs += ['src/main/kotlin', 'src/main/java']
}
}
test {
java {
srcDirs += []
}
kotlin {
srcDirs += ['src/main/kotlin', 'src/main/java']
}
}
}
compileKotlin {
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8
}
compileTestKotlin {
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8
}
dependencies {
api "com.android.tools.build:gradle:$agp_version"
/* 👇👇👇👇 引用这两个模块 👇👇👇👇 */
kapt "com.google.auto.service:auto-service:1.0"
api "com.didiglobal.booster:booster-api:$booster_version"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
基于 ASM
基于 ASM 的 ClassTransformer 需要在 dependencies
中引入 booster-transform-asm在新窗口打开 依赖:
dependencies {
api "com.android.tools.build:gradle:$agp_version"
/* 👇👇👇👇 引用这三个模块 👇👇👇👇 */
kapt "com.google.auto.service:auto-service:1.0"
api "com.didiglobal.booster:booster-api:$booster_version"
api "com.didiglobal.booster:booster-transform-asm:$booster_version"
}
2
3
4
5
6
7
package io.johnsonlee.booster.demo
import com.didiglobal.booster.transform.TransformContext
import com.didiglobal.booster.transform.asm.ClassTransformer
import org.objectweb.asm.tree.ClassNode
import com.google.auto.service.AutoService
@AutoService(ClassTransformer::class)
class FirstClassTransformer : ClassTransformer {
override fun transform(context: TransformContext, klass: ClassNode): ClassNode {
println("Transforming ${klass.name}")
return klass
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
基于 Javassist
基于 Javassist 的 ClassTransformer 需要在 dependencies
中引入 booster-transform-javassist在新窗口打开 依赖:
dependencies {
api "com.android.tools.build:gradle:$agp_version"
/* 👇👇👇👇 引用这三个模块 👇👇👇👇 */
kapt "com.google.auto.service:auto-service:1.0"
api "com.didiglobal.booster:booster-api:$booster_version"
api "com.didiglobal.booster:booster-transform-javassist:$booster_version"
}
2
3
4
5
6
7
package io.johnsonlee.booster.demo
import com.didiglobal.booster.transform.TransformContext
import com.didiglobal.booster.transform.javassist.ClassTransformer
import com.google.auto.service.AutoService
import javassist.CtClass
@AutoService(ClassTransformer::class)
class FirstClassTransformer : ClassTransformer {
override fun transform(context: TransformContext, klass: CtClass): CtClass {
println("Transforming ${klass.name}")
return klass
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
配置 Android 工程
至此,第一个 ClassTransformer 基本完成,接下来在 Android 工程的 build.gradle 中配置 Booster:
buildscript {
ext {
agp_version = "4.0.0"
booster_version = "4.16.3"
kotlin_version = "1.5.31"
}
repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
classpath "com.android.tools.build:gradle:$agp_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
/* 👇👇👇👇 引用 Booster Gradle 插件 👇👇👇👇 */
classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
}
}
allprojects {
repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
/* 👇👇👇👇 应用 Booster 插件 👇👇👇👇 */
apply plugin: 'com.didiglobal.booster'
android {
compileSdkVersion 28
buildToolsVersion "26.0.3"
defaultConfig {
applicationId 'io.johnsonlee.booster.demo'
minSdkVersion 18
targetSdkVersion 26
versionCode 1
versionName '1.0'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.appcompat:appcompat:${jetpack_appcompat_version}"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
验证 FirstClassTransformer
在 Android 工程下,执行 assemble 任务:
$ ./gradlew assembleDebug
观察控制台的标准输出,是否有如下内容:
Transforming kotlinx/android/parcel/TypeParceler
Transforming androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompat$1
Transforming androidx/appcompat/app/ActionBar$NavigationMode
Transforming kotlinx/android/parcel/WriteWith
Transforming kotlinx/android/parcel/IgnoredOnParcel
Transforming kotlinx/android/parcel/RawValue
Transforming kotlinx/android/parcel/Parcelize
Transforming androidx/appcompat/app/ActionBar$DisplayOptions
Transforming kotlinx/android/extensions/LayoutContainer
Transforming androidx/appcompat/app/ActionBarDrawerToggle$Delegate
Transforming androidx/appcompat/app/ActionBar$TabListener
Transforming androidx/appcompat/app/ActionBar$OnMenuVisibilityListener
Transforming kotlin/jvm/internal/Ref$DoubleRef
......
2
3
4
5
6
7
8
9
10
11
12
13
14