android-sdd 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +143 -0
- package/package.json +27 -0
- package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
- package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
- package/skills/Android Platform/Configuration/SKILL.md +201 -0
- package/skills/Android Platform/Filesystem/SKILL.md +216 -0
- package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
- package/skills/Android Platform/Manifest/SKILL.md +226 -0
- package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
- package/skills/Android Platform/Resources/SKILL.md +234 -0
- package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
- package/skills/Android Platform/State Restoration/SKILL.md +210 -0
- package/skills/Architecture/Bounded Context/SKILL.md +207 -0
- package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
- package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
- package/skills/Architecture/Entity Design/SKILL.md +243 -0
- package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
- package/skills/Architecture/MVI/SKILL.md +224 -0
- package/skills/Architecture/MVVM/SKILL.md +198 -0
- package/skills/Architecture/Modularization/SKILL.md +194 -0
- package/skills/Architecture/Offline First/SKILL.md +249 -0
- package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
- package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
- package/skills/Architecture/State Management/SKILL.md +229 -0
- package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
- package/skills/Architecture/Use Case Design/SKILL.md +244 -0
- package/skills/Architecture/Value Object/SKILL.md +226 -0
- package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
- package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
- package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
- package/skills/Build System/Build Cache/SKILL.md +233 -0
- package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
- package/skills/Build System/Build Variant/SKILL.md +215 -0
- package/skills/Build System/Convention Plugin/SKILL.md +288 -0
- package/skills/Build System/Dependency Management/SKILL.md +261 -0
- package/skills/Build System/Gradle/SKILL.md +284 -0
- package/skills/Build System/Incremental Build/SKILL.md +199 -0
- package/skills/Build System/KAPT/SKILL.md +198 -0
- package/skills/Build System/KSP/SKILL.md +263 -0
- package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
- package/skills/Build System/Specialized/C++/SKILL.md +308 -0
- package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
- package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
- package/skills/Build System/Version Catalog/SKILL.md +304 -0
- package/skills/Concurrency/Background Processing/SKILL.md +185 -0
- package/skills/Concurrency/Channel/SKILL.md +207 -0
- package/skills/Concurrency/Coroutine/SKILL.md +200 -0
- package/skills/Concurrency/Flow/SKILL.md +179 -0
- package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
- package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
- package/skills/Concurrency/StateFlow/SKILL.md +175 -0
- package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
- package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
- package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
- package/skills/Core Language/DSL/SKILL.md +186 -0
- package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
- package/skills/Core Language/Immutability/SKILL.md +156 -0
- package/skills/Core Language/KMP/SKILL.md +182 -0
- package/skills/Core Language/Kotlin/SKILL.md +187 -0
- package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
- package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
- package/skills/Core Language/Serialization/SKILL.md +191 -0
- package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
- package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
- package/skills/Data Layer/DAO/SKILL.md +225 -0
- package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
- package/skills/Data Layer/DataStore/SKILL.md +264 -0
- package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
- package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
- package/skills/Data Layer/File Storage/SKILL.md +247 -0
- package/skills/Data Layer/Indexing/SKILL.md +184 -0
- package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
- package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
- package/skills/Data Layer/Migration/SKILL.md +243 -0
- package/skills/Data Layer/Paging/SKILL.md +264 -0
- package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
- package/skills/Data Layer/Room/SKILL.md +244 -0
- package/skills/Data Layer/SQLite/SKILL.md +255 -0
- package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
- package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
- package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
- package/skills/Dependency Injection/Koin/SKILL.md +282 -0
- package/skills/Developer Experience/Detekt/SKILL.md +272 -0
- package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
- package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
- package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
- package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
- package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
- package/skills/Media/Audio/SKILL.md +257 -0
- package/skills/Media/Camera/SKILL.md +229 -0
- package/skills/Media/CameraX/SKILL.md +295 -0
- package/skills/Media/ExoPlayer/SKILL.md +258 -0
- package/skills/Media/Video/SKILL.md +228 -0
- package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
- package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
- package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
- package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
- package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
- package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
- package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
- package/skills/Navigation/Navigation/SKILL.md +215 -0
- package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
- package/skills/Networking/API Contract/SKILL.md +220 -0
- package/skills/Networking/Authentication/SKILL.md +210 -0
- package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
- package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
- package/skills/Networking/Ktor/SKILL.md +219 -0
- package/skills/Networking/Multipart Upload/SKILL.md +213 -0
- package/skills/Networking/OkHttp/SKILL.md +193 -0
- package/skills/Networking/REST/SKILL.md +178 -0
- package/skills/Networking/Rate Limiting/SKILL.md +170 -0
- package/skills/Networking/Retrofit/SKILL.md +241 -0
- package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
- package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
- package/skills/Networking/WebSocket/SKILL.md +224 -0
- package/skills/Observability/Crash Reporting/SKILL.md +219 -0
- package/skills/Observability/Logging/SKILL.md +168 -0
- package/skills/Observability/Metrics/SKILL.md +227 -0
- package/skills/Observability/Structured Logging/SKILL.md +234 -0
- package/skills/Performance/ANR Prevention/SKILL.md +192 -0
- package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
- package/skills/Performance/App Startup/SKILL.md +183 -0
- package/skills/Performance/Baseline Profile/SKILL.md +205 -0
- package/skills/Performance/Battery Optimization/SKILL.md +192 -0
- package/skills/Performance/Benchmark/SKILL.md +182 -0
- package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
- package/skills/Performance/Compose Optimization/SKILL.md +187 -0
- package/skills/Performance/Heap Management/SKILL.md +184 -0
- package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
- package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
- package/skills/Performance/Rendering Performance/SKILL.md +205 -0
- package/skills/Performance/Startup Optimization/SKILL.md +219 -0
- package/skills/Security/Biometric/SKILL.md +224 -0
- package/skills/Security/Certificate Transparency/SKILL.md +158 -0
- package/skills/Security/Cryptography/SKILL.md +244 -0
- package/skills/Security/Encrypted Storage/SKILL.md +273 -0
- package/skills/Security/Frida Detection/SKILL.md +230 -0
- package/skills/Security/Hook Detection/SKILL.md +197 -0
- package/skills/Security/Keystore/SKILL.md +272 -0
- package/skills/Security/Network Security Config/SKILL.md +186 -0
- package/skills/Security/Obfuscation/SKILL.md +226 -0
- package/skills/Security/Proguard/SKILL.md +202 -0
- package/skills/Security/R8/SKILL.md +234 -0
- package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
- package/skills/Security/Root Detection/SKILL.md +220 -0
- package/skills/Security/Secure Networking/SKILL.md +220 -0
- package/skills/System Integration/AlarmManager/SKILL.md +182 -0
- package/skills/System Integration/App Widget/SKILL.md +182 -0
- package/skills/System Integration/Deep Link/SKILL.md +187 -0
- package/skills/System Integration/Foreground Service/SKILL.md +212 -0
- package/skills/System Integration/Notification/SKILL.md +237 -0
- package/skills/System Integration/WorkManager/SKILL.md +256 -0
- package/skills/System Integration/clipboard/SKILL.md +155 -0
- package/skills/System Integration/share-intent/SKILL.md +182 -0
- package/skills/Testing/Compose Testing/SKILL.md +296 -0
- package/skills/Testing/Espresso/SKILL.md +292 -0
- package/skills/Testing/Fake Data/SKILL.md +245 -0
- package/skills/Testing/Integration Testing/SKILL.md +288 -0
- package/skills/Testing/Mocking/SKILL.md +229 -0
- package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
- package/skills/Testing/UI Testing/SKILL.md +293 -0
- package/skills/Testing/Unit Testing/SKILL.md +309 -0
- package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
- package/skills/UI System/Compose/SKILL.md +296 -0
- package/skills/UI System/Compose Animation/SKILL.md +281 -0
- package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
- package/skills/UI System/Compose Navigation/SKILL.md +255 -0
- package/skills/UI System/Compose Performance/SKILL.md +274 -0
- package/skills/UI System/Design System/SKILL.md +217 -0
- package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
- package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
- package/skills/UI System/Loading Strategy/SKILL.md +254 -0
- package/skills/UI System/Material 3/SKILL.md +279 -0
- package/skills/UI System/RTL/SKILL.md +179 -0
- package/src/index.ts +182 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: incremental-build
|
|
3
|
+
description: >
|
|
4
|
+
Gradle incremental build configuration for Android.
|
|
5
|
+
Load this skill when optimizing build times, understanding why builds
|
|
6
|
+
aren't incremental, or configuring tasks for incremental processing.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Incremental Build
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
Gradle's incremental build system skips tasks whose inputs and outputs haven't changed. In a properly configured project, only affected modules and tasks re-run after a change. Incremental builds can reduce build time from minutes to seconds.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Core Principles
|
|
17
|
+
|
|
18
|
+
- Gradle skips tasks when **inputs and outputs are unchanged** — the UP-TO-DATE check
|
|
19
|
+
- Tasks must declare their **inputs and outputs** explicitly for incrementality to work
|
|
20
|
+
- **Configuration cache** skips the configuration phase on subsequent builds
|
|
21
|
+
- **Build cache** reuses task outputs across machines (local and remote)
|
|
22
|
+
- Any task that's not incremental becomes a **build bottleneck**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## gradle.properties Configuration
|
|
27
|
+
|
|
28
|
+
```properties
|
|
29
|
+
# ✅ Enable all incremental build features
|
|
30
|
+
org.gradle.parallel=true # parallel task execution
|
|
31
|
+
org.gradle.caching=true # local build cache
|
|
32
|
+
org.gradle.configuration-cache=true # cache configuration phase
|
|
33
|
+
org.gradle.configuration-cache.problems=warn # warn instead of fail on problems
|
|
34
|
+
org.gradle.daemon=true # keep Gradle daemon alive
|
|
35
|
+
org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Understanding Task States
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Task output states
|
|
44
|
+
# UP-TO-DATE → inputs/outputs unchanged, task skipped ✅
|
|
45
|
+
# FROM-CACHE → output restored from build cache ✅
|
|
46
|
+
# NO-SOURCE → no input sources, task skipped ✅
|
|
47
|
+
# SKIPPED → task condition not met (e.g., disabled) ✅
|
|
48
|
+
# EXECUTED → task ran (not incremental) ⚠️
|
|
49
|
+
|
|
50
|
+
./gradlew assembleDebug --info | grep "Task :"
|
|
51
|
+
# Look for: Task :app:compileDebugKotlin UP-TO-DATE
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## What Breaks Incrementality
|
|
57
|
+
|
|
58
|
+
```kotlin
|
|
59
|
+
// ❌ Reading System.currentTimeMillis() in a task — always changes
|
|
60
|
+
tasks.register("generateBuildInfo") {
|
|
61
|
+
doLast {
|
|
62
|
+
val file = File(outputDir, "build_info.txt")
|
|
63
|
+
file.writeText("Built at: ${System.currentTimeMillis()}") // NOT incremental
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ✅ Declare inputs/outputs properly
|
|
68
|
+
abstract class GenerateBuildInfoTask : DefaultTask() {
|
|
69
|
+
@get:Input abstract val buildTimestamp: Property<Long>
|
|
70
|
+
@get:OutputFile abstract val outputFile: RegularFileProperty
|
|
71
|
+
|
|
72
|
+
@TaskAction
|
|
73
|
+
fun generate() {
|
|
74
|
+
outputFile.get().asFile.writeText("Built at: ${buildTimestamp.get()}")
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ✅ Only changes when buildTimestamp input changes
|
|
79
|
+
tasks.register<GenerateBuildInfoTask>("generateBuildInfo") {
|
|
80
|
+
buildTimestamp.set(System.currentTimeMillis())
|
|
81
|
+
outputFile.set(layout.buildDirectory.file("generated/build_info.txt"))
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## KSP Incremental Processing
|
|
88
|
+
|
|
89
|
+
```kotlin
|
|
90
|
+
// ✅ KSP is incremental by default
|
|
91
|
+
// Room and Hilt benefit automatically
|
|
92
|
+
|
|
93
|
+
// ✅ Explicit Room incremental config
|
|
94
|
+
ksp {
|
|
95
|
+
arg("room.incremental", "true")
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Avoiding Configuration Cache Problems
|
|
102
|
+
|
|
103
|
+
```kotlin
|
|
104
|
+
// ❌ Accessing project at execution time — breaks config cache
|
|
105
|
+
tasks.register("badTask") {
|
|
106
|
+
doLast {
|
|
107
|
+
println(project.version) // project accessed at execution — breaks config cache
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ✅ Capture at configuration time
|
|
112
|
+
tasks.register("goodTask") {
|
|
113
|
+
val version = project.version.toString() // captured at config time
|
|
114
|
+
doLast {
|
|
115
|
+
println(version)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ❌ Using Task.project inside doLast
|
|
120
|
+
tasks.named("assemble") {
|
|
121
|
+
doLast {
|
|
122
|
+
project.copy { ... } // breaks config cache
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ✅ Use injected services instead
|
|
127
|
+
abstract class MyTask @Inject constructor(
|
|
128
|
+
private val fs: FileSystemOperations
|
|
129
|
+
) : DefaultTask() {
|
|
130
|
+
@TaskAction fun run() { fs.copy { ... } }
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Checking Build Cache Effectiveness
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# ✅ Run build twice — second should be FROM-CACHE
|
|
140
|
+
./gradlew assembleDebug
|
|
141
|
+
./gradlew clean
|
|
142
|
+
./gradlew assembleDebug
|
|
143
|
+
# Expected: tasks show FROM-CACHE
|
|
144
|
+
|
|
145
|
+
# ✅ Build scan — detailed incrementality report
|
|
146
|
+
./gradlew assembleDebug --scan
|
|
147
|
+
# Shows which tasks ran and why
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Module-Level Incrementality
|
|
153
|
+
|
|
154
|
+
```kotlin
|
|
155
|
+
// ✅ Modularization is the biggest win for incremental builds
|
|
156
|
+
// Only modules with changed files recompile
|
|
157
|
+
|
|
158
|
+
// ✅ Use implementation() not api() — api() propagates recompilation
|
|
159
|
+
// Changing a type in api() triggers recompilation of all consumers
|
|
160
|
+
// Changing a type in implementation() only recompiles that module
|
|
161
|
+
|
|
162
|
+
// ✅ Minimize module dependencies
|
|
163
|
+
// Feature modules should depend only on :core:* not on each other
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Build Performance Profiling
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# ✅ Profile report (HTML)
|
|
172
|
+
./gradlew assembleDebug --profile
|
|
173
|
+
# Output: build/reports/profile/
|
|
174
|
+
|
|
175
|
+
# ✅ Build scan (detailed, online)
|
|
176
|
+
./gradlew assembleDebug --scan
|
|
177
|
+
|
|
178
|
+
# ✅ Find slowest tasks
|
|
179
|
+
./gradlew assembleDebug --profile 2>&1 | grep "ms" | sort -rn | head -20
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Anti-Patterns
|
|
185
|
+
|
|
186
|
+
- Not enabling `org.gradle.caching=true` — cache never used
|
|
187
|
+
- Tasks without declared inputs/outputs — always EXECUTED, never UP-TO-DATE
|
|
188
|
+
- Reading external state (time, random, env vars) inside task actions without declaring as input
|
|
189
|
+
- `api()` dependencies everywhere — breaks incremental compilation between modules
|
|
190
|
+
- Disabling the Gradle daemon — cold start every build
|
|
191
|
+
- Not enabling configuration cache — configuration phase re-runs every build
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Related Skills
|
|
196
|
+
- `build-cache` — local and remote build cache
|
|
197
|
+
- `gradle` — Gradle fundamentals
|
|
198
|
+
- `convention-plugin` — consistent task configuration across modules
|
|
199
|
+
- `modularization` — module structure for incremental builds
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kapt
|
|
3
|
+
description: >
|
|
4
|
+
Kotlin Annotation Processing Tool (KAPT) setup and usage for Android.
|
|
5
|
+
Load this skill when working with libraries that haven't migrated to KSP yet,
|
|
6
|
+
configuring KAPT options, or understanding why KAPT is slower than KSP.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# KAPT (Kotlin Annotation Processing Tool)
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
KAPT is the legacy annotation processing framework for Kotlin. It works by generating Java stubs from Kotlin code and then running Java annotation processors on them. This two-step process makes KAPT significantly slower than KSP. Use KAPT only when a library has no KSP support yet.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Core Principles
|
|
17
|
+
|
|
18
|
+
- **Prefer KSP over KAPT** whenever possible — KSP is 2x faster
|
|
19
|
+
- Use KAPT only for libraries that **haven't migrated to KSP**
|
|
20
|
+
- Never use both KAPT and KSP for the **same library** in the same module
|
|
21
|
+
- KAPT is not compatible with **Kotlin Multiplatform** — use KSP for KMP
|
|
22
|
+
- Track library KSP migration status — switch when available
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## When to Use KAPT
|
|
27
|
+
|
|
28
|
+
| Library | KAPT | KSP |
|
|
29
|
+
|---------|------|-----|
|
|
30
|
+
| Hilt | Legacy | ✅ Use KSP |
|
|
31
|
+
| Room | Legacy | ✅ Use KSP |
|
|
32
|
+
| Moshi Codegen | Legacy | ✅ Use KSP |
|
|
33
|
+
| Glide | ✅ Still KAPT | ❌ No KSP yet |
|
|
34
|
+
| Dagger (without Hilt) | ✅ Still KAPT | Partial |
|
|
35
|
+
| Some third-party libs | ✅ Check | Check |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Setup
|
|
40
|
+
|
|
41
|
+
```kotlin
|
|
42
|
+
// build.gradle.kts
|
|
43
|
+
plugins {
|
|
44
|
+
kotlin("kapt") // apply KAPT plugin
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
dependencies {
|
|
48
|
+
// ✅ Use kapt() configuration for annotation processors
|
|
49
|
+
kapt(libs.glide.compiler)
|
|
50
|
+
kapt(libs.some.legacy.compiler)
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## KAPT Configuration Options
|
|
57
|
+
|
|
58
|
+
```kotlin
|
|
59
|
+
// build.gradle.kts
|
|
60
|
+
kapt {
|
|
61
|
+
// ✅ Enable incremental processing (limited — less effective than KSP)
|
|
62
|
+
useBuildCache = true
|
|
63
|
+
|
|
64
|
+
// ✅ Correct error types — helps KAPT work with complex generics
|
|
65
|
+
correctErrorTypes = true
|
|
66
|
+
|
|
67
|
+
// ✅ Pass arguments to processors
|
|
68
|
+
arguments {
|
|
69
|
+
arg("dagger.fastInit", "enabled")
|
|
70
|
+
arg("dagger.experimentalDaggerErrorMessages", "enabled")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ✅ Show processor warnings
|
|
74
|
+
showProcessorStats = true
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## KAPT vs KSP Performance
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
KAPT Build Flow:
|
|
84
|
+
1. Kotlin → Java stubs (slow)
|
|
85
|
+
2. Java annotation processors run on stubs (slow)
|
|
86
|
+
3. Generated Java code compiled
|
|
87
|
+
4. Kotlin code compiled
|
|
88
|
+
|
|
89
|
+
KSP Build Flow:
|
|
90
|
+
1. KSP processors run directly on Kotlin symbols (fast)
|
|
91
|
+
2. Generated Kotlin code compiled together
|
|
92
|
+
|
|
93
|
+
Result: KSP is typically 2x faster than KAPT
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Incremental KAPT (Limited)
|
|
99
|
+
|
|
100
|
+
```kotlin
|
|
101
|
+
// ✅ Enable incremental annotation processing in KAPT
|
|
102
|
+
// Note: much less effective than KSP's incremental processing
|
|
103
|
+
kapt {
|
|
104
|
+
useBuildCache = true
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// gradle.properties
|
|
108
|
+
kapt.incremental.apt=true
|
|
109
|
+
kapt.use.worker.api=true
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Migrating from KAPT to KSP
|
|
115
|
+
|
|
116
|
+
```kotlin
|
|
117
|
+
// Step 1: Remove KAPT plugin (if no more KAPT processors remain)
|
|
118
|
+
// plugins { kotlin("kapt") } // remove
|
|
119
|
+
|
|
120
|
+
// Step 2: Add KSP plugin
|
|
121
|
+
plugins {
|
|
122
|
+
alias(libs.plugins.ksp)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Step 3: Replace kapt() with ksp() for each processor
|
|
126
|
+
// Before:
|
|
127
|
+
kapt(libs.hilt.compiler)
|
|
128
|
+
kapt(libs.androidx.room.compiler)
|
|
129
|
+
|
|
130
|
+
// After:
|
|
131
|
+
ksp(libs.hilt.compiler)
|
|
132
|
+
ksp(libs.androidx.room.compiler)
|
|
133
|
+
|
|
134
|
+
// Step 4: Update KSP-specific config if needed
|
|
135
|
+
ksp {
|
|
136
|
+
arg("room.schemaLocation", "$projectDir/schemas")
|
|
137
|
+
arg("room.incremental", "true")
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Mixing KAPT and KSP (When Unavoidable)
|
|
144
|
+
|
|
145
|
+
```kotlin
|
|
146
|
+
// ✅ OK — different libraries, different processors
|
|
147
|
+
plugins {
|
|
148
|
+
alias(libs.plugins.ksp) // for Room, Hilt
|
|
149
|
+
kotlin("kapt") // for Glide (no KSP yet)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
dependencies {
|
|
153
|
+
ksp(libs.hilt.compiler) // KSP
|
|
154
|
+
ksp(libs.androidx.room.compiler) // KSP
|
|
155
|
+
kapt(libs.glide.compiler) // KAPT — no KSP alternative yet
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ❌ NOT OK — same library using both
|
|
159
|
+
ksp(libs.hilt.compiler) // ❌
|
|
160
|
+
kapt(libs.hilt.compiler) // ❌ — pick one
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Debugging KAPT Issues
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# ✅ Enable verbose KAPT output
|
|
169
|
+
./gradlew assembleDebug --info 2>&1 | grep -i "kapt"
|
|
170
|
+
|
|
171
|
+
# ✅ See processor output
|
|
172
|
+
./gradlew assembleDebug -Dkapt.verbose=true
|
|
173
|
+
|
|
174
|
+
# ✅ Check generated stubs
|
|
175
|
+
# build/tmp/kapt3/stubs/debug/
|
|
176
|
+
|
|
177
|
+
# ✅ Check generated sources
|
|
178
|
+
# build/generated/source/kapt/debug/
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Anti-Patterns
|
|
184
|
+
|
|
185
|
+
- Using KAPT for libraries that have KSP support — unnecessary slowdown
|
|
186
|
+
- Mixing KAPT and KSP for the same library — one will be ignored or conflict
|
|
187
|
+
- Not setting `correctErrorTypes = true` — obscure compilation errors with complex types
|
|
188
|
+
- Keeping KAPT plugin when all processors have migrated to KSP — dead weight
|
|
189
|
+
- Using KAPT in KMP modules — it's not supported, use KSP
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Related Skills
|
|
194
|
+
- `ksp` — modern alternative to KAPT (preferred)
|
|
195
|
+
- `annotation-processing` — annotation processing patterns
|
|
196
|
+
- `gradle` — plugin configuration
|
|
197
|
+
- `hilt` — Hilt now uses KSP
|
|
198
|
+
- `room` — Room now uses KSP
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ksp
|
|
3
|
+
description: >
|
|
4
|
+
Kotlin Symbol Processing (KSP) setup and usage for Android.
|
|
5
|
+
Load this skill when configuring KSP for code generation libraries
|
|
6
|
+
(Room, Hilt, Moshi), writing custom KSP processors, or migrating
|
|
7
|
+
from KAPT to KSP.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# KSP (Kotlin Symbol Processing)
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
KSP is Kotlin's modern annotation processing framework. It replaces KAPT, is up to 2x faster, supports incremental processing, and works with Kotlin Multiplatform. Most major Android libraries (Room, Hilt, Moshi) have migrated to KSP.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- **Always prefer KSP over KAPT** for new code and when migrating
|
|
20
|
+
- Never mix KSP and KAPT for the **same library** in the same module
|
|
21
|
+
- KSP generates code in `build/generated/ksp/` — never edit generated files
|
|
22
|
+
- KSP configuration goes in the `ksp {}` block — not in `android {}`
|
|
23
|
+
- Enable incremental processing for large codebases
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
# libs.versions.toml
|
|
31
|
+
[versions]
|
|
32
|
+
ksp = "2.0.0-1.0.21"
|
|
33
|
+
|
|
34
|
+
[plugins]
|
|
35
|
+
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```kotlin
|
|
39
|
+
// build.gradle.kts (module)
|
|
40
|
+
plugins {
|
|
41
|
+
alias(libs.plugins.ksp)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
dependencies {
|
|
45
|
+
// ✅ KSP-based processors
|
|
46
|
+
ksp(libs.hilt.compiler)
|
|
47
|
+
ksp(libs.androidx.room.compiler)
|
|
48
|
+
ksp(libs.moshi.kotlin.codegen)
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## KSP Configuration per Library
|
|
55
|
+
|
|
56
|
+
```kotlin
|
|
57
|
+
// ✅ Room — schema export and incremental processing
|
|
58
|
+
ksp {
|
|
59
|
+
arg("room.schemaLocation", "$projectDir/schemas")
|
|
60
|
+
arg("room.incremental", "true")
|
|
61
|
+
arg("room.expandProjection", "true")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ✅ Moshi — codegen options
|
|
65
|
+
ksp {
|
|
66
|
+
arg("moshi.generateProguardRules", "true")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ✅ Auto Factory — if using Dagger's factory generation
|
|
70
|
+
ksp {
|
|
71
|
+
arg("dagger.fastInit", "enabled")
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## KSP in Multi-Module Projects
|
|
78
|
+
|
|
79
|
+
```kotlin
|
|
80
|
+
// ✅ Apply KSP plugin only in modules that use it
|
|
81
|
+
// feature/home/build.gradle.kts
|
|
82
|
+
plugins {
|
|
83
|
+
id("myapp.android.library")
|
|
84
|
+
id("myapp.android.hilt") // convention plugin applies ksp + hilt.compiler
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ✅ Convention plugin handling KSP setup
|
|
88
|
+
class AndroidHiltConventionPlugin : Plugin<Project> {
|
|
89
|
+
override fun apply(target: Project) {
|
|
90
|
+
with(target) {
|
|
91
|
+
pluginManager.apply("com.google.devtools.ksp")
|
|
92
|
+
dependencies {
|
|
93
|
+
add("ksp", libs.findLibrary("hilt-compiler").get())
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## KSP in KMP Projects
|
|
103
|
+
|
|
104
|
+
```kotlin
|
|
105
|
+
// ✅ KSP works in KMP — specify target
|
|
106
|
+
kotlin {
|
|
107
|
+
sourceSets {
|
|
108
|
+
commonMain.dependencies {
|
|
109
|
+
implementation(libs.room.runtime)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
dependencies {
|
|
115
|
+
// ✅ KSP for specific KMP targets
|
|
116
|
+
add("kspAndroid", libs.androidx.room.compiler)
|
|
117
|
+
add("kspJvm", libs.androidx.room.compiler)
|
|
118
|
+
// add("kspIos...", libs.androidx.room.compiler) // if supporting iOS
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## KAPT to KSP Migration
|
|
125
|
+
|
|
126
|
+
```kotlin
|
|
127
|
+
// ✅ Migration steps per library
|
|
128
|
+
|
|
129
|
+
// Room — was KAPT
|
|
130
|
+
kapt(libs.androidx.room.compiler)
|
|
131
|
+
// → now KSP
|
|
132
|
+
ksp(libs.androidx.room.compiler)
|
|
133
|
+
|
|
134
|
+
// Hilt — was KAPT
|
|
135
|
+
kapt(libs.hilt.compiler)
|
|
136
|
+
// → now KSP
|
|
137
|
+
ksp(libs.hilt.compiler)
|
|
138
|
+
|
|
139
|
+
// Moshi Codegen — was KAPT
|
|
140
|
+
kapt(libs.moshi.kotlin.codegen)
|
|
141
|
+
// → now KSP
|
|
142
|
+
ksp(libs.moshi.kotlin.codegen)
|
|
143
|
+
|
|
144
|
+
// ✅ Remove KAPT plugin after migration
|
|
145
|
+
// plugins { kotlin("kapt") } // remove this
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Writing a Custom KSP Processor
|
|
151
|
+
|
|
152
|
+
```kotlin
|
|
153
|
+
// ✅ Implement SymbolProcessor
|
|
154
|
+
class MyProcessor(
|
|
155
|
+
private val codeGenerator: CodeGenerator,
|
|
156
|
+
private val logger: KSPLogger,
|
|
157
|
+
private val options: Map<String, String>
|
|
158
|
+
) : SymbolProcessor {
|
|
159
|
+
|
|
160
|
+
override fun process(resolver: Resolver): List<KSAnnotated> {
|
|
161
|
+
val symbols = resolver
|
|
162
|
+
.getSymbolsWithAnnotation("com.example.MyAnnotation")
|
|
163
|
+
.filterIsInstance<KSClassDeclaration>()
|
|
164
|
+
|
|
165
|
+
val unprocessed = mutableListOf<KSAnnotated>()
|
|
166
|
+
|
|
167
|
+
symbols.forEach { classDecl ->
|
|
168
|
+
if (!classDecl.validate()) {
|
|
169
|
+
unprocessed.add(classDecl)
|
|
170
|
+
return@forEach
|
|
171
|
+
}
|
|
172
|
+
generateCode(classDecl)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return unprocessed
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private fun generateCode(classDecl: KSClassDeclaration) {
|
|
179
|
+
val packageName = classDecl.packageName.asString()
|
|
180
|
+
val className = "${classDecl.simpleName.asString()}Generated"
|
|
181
|
+
|
|
182
|
+
codeGenerator.createNewFile(
|
|
183
|
+
dependencies = Dependencies(false, classDecl.containingFile!!),
|
|
184
|
+
packageName = packageName,
|
|
185
|
+
fileName = className
|
|
186
|
+
).use { stream ->
|
|
187
|
+
stream.write(
|
|
188
|
+
"""
|
|
189
|
+
package $packageName
|
|
190
|
+
|
|
191
|
+
class $className {
|
|
192
|
+
fun hello() = "Generated for ${classDecl.simpleName.asString()}"
|
|
193
|
+
}
|
|
194
|
+
""".trimIndent().toByteArray()
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ✅ Provider — registers the processor
|
|
201
|
+
class MyProcessorProvider : SymbolProcessorProvider {
|
|
202
|
+
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
|
|
203
|
+
MyProcessor(
|
|
204
|
+
codeGenerator = environment.codeGenerator,
|
|
205
|
+
logger = environment.logger,
|
|
206
|
+
options = environment.options
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
# Register in resources/META-INF/services/
|
|
213
|
+
# com.google.devtools.ksp.processing.SymbolProcessorProvider
|
|
214
|
+
com.example.processor.MyProcessorProvider
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Viewing Generated Code
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Generated code location
|
|
223
|
+
build/generated/ksp/<variant>/kotlin/
|
|
224
|
+
|
|
225
|
+
# Example for Room
|
|
226
|
+
build/generated/ksp/debug/kotlin/com/example/UserDao_Impl.kt
|
|
227
|
+
|
|
228
|
+
# ✅ Never edit — regenerated on every build
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Incremental Processing
|
|
234
|
+
|
|
235
|
+
```kotlin
|
|
236
|
+
// ✅ KSP is incremental by default
|
|
237
|
+
// Only reprocesses files that changed
|
|
238
|
+
|
|
239
|
+
// For custom processors — declare incremental support
|
|
240
|
+
class MyProcessor(...) : SymbolProcessor {
|
|
241
|
+
// Returning unprocessed symbols from process() is the incremental contract
|
|
242
|
+
// Symbols that can't be processed yet are returned and retried
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Anti-Patterns
|
|
249
|
+
|
|
250
|
+
- Using KAPT when KSP is available — 2x slower builds
|
|
251
|
+
- Mixing KAPT and KSP for the same library — one will be ignored or conflict
|
|
252
|
+
- Applying KSP plugin to modules that don't use it — unnecessary overhead
|
|
253
|
+
- Editing files in `build/generated/ksp/` — overwritten on next build
|
|
254
|
+
- Not configuring `room.schemaLocation` — migrations can't be written or tested
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Related Skills
|
|
259
|
+
- `annotation-processing` — broader annotation processing patterns
|
|
260
|
+
- `room` — Room database with KSP compiler
|
|
261
|
+
- `hilt` — Hilt DI with KSP setup
|
|
262
|
+
- `gradle` — Gradle plugin configuration
|
|
263
|
+
- `kmp` — KSP in multiplatform projects
|