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.
Files changed (176) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +27 -0
  3. package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
  4. package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
  5. package/skills/Android Platform/Configuration/SKILL.md +201 -0
  6. package/skills/Android Platform/Filesystem/SKILL.md +216 -0
  7. package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
  8. package/skills/Android Platform/Manifest/SKILL.md +226 -0
  9. package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
  10. package/skills/Android Platform/Resources/SKILL.md +234 -0
  11. package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
  12. package/skills/Android Platform/State Restoration/SKILL.md +210 -0
  13. package/skills/Architecture/Bounded Context/SKILL.md +207 -0
  14. package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
  15. package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
  16. package/skills/Architecture/Entity Design/SKILL.md +243 -0
  17. package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
  18. package/skills/Architecture/MVI/SKILL.md +224 -0
  19. package/skills/Architecture/MVVM/SKILL.md +198 -0
  20. package/skills/Architecture/Modularization/SKILL.md +194 -0
  21. package/skills/Architecture/Offline First/SKILL.md +249 -0
  22. package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
  23. package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
  24. package/skills/Architecture/State Management/SKILL.md +229 -0
  25. package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
  26. package/skills/Architecture/Use Case Design/SKILL.md +244 -0
  27. package/skills/Architecture/Value Object/SKILL.md +226 -0
  28. package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
  29. package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
  30. package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
  31. package/skills/Build System/Build Cache/SKILL.md +233 -0
  32. package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
  33. package/skills/Build System/Build Variant/SKILL.md +215 -0
  34. package/skills/Build System/Convention Plugin/SKILL.md +288 -0
  35. package/skills/Build System/Dependency Management/SKILL.md +261 -0
  36. package/skills/Build System/Gradle/SKILL.md +284 -0
  37. package/skills/Build System/Incremental Build/SKILL.md +199 -0
  38. package/skills/Build System/KAPT/SKILL.md +198 -0
  39. package/skills/Build System/KSP/SKILL.md +263 -0
  40. package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
  41. package/skills/Build System/Specialized/C++/SKILL.md +308 -0
  42. package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
  43. package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
  44. package/skills/Build System/Version Catalog/SKILL.md +304 -0
  45. package/skills/Concurrency/Background Processing/SKILL.md +185 -0
  46. package/skills/Concurrency/Channel/SKILL.md +207 -0
  47. package/skills/Concurrency/Coroutine/SKILL.md +200 -0
  48. package/skills/Concurrency/Flow/SKILL.md +179 -0
  49. package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
  50. package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
  51. package/skills/Concurrency/StateFlow/SKILL.md +175 -0
  52. package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
  53. package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
  54. package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
  55. package/skills/Core Language/DSL/SKILL.md +186 -0
  56. package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
  57. package/skills/Core Language/Immutability/SKILL.md +156 -0
  58. package/skills/Core Language/KMP/SKILL.md +182 -0
  59. package/skills/Core Language/Kotlin/SKILL.md +187 -0
  60. package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
  61. package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
  62. package/skills/Core Language/Serialization/SKILL.md +191 -0
  63. package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
  64. package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
  65. package/skills/Data Layer/DAO/SKILL.md +225 -0
  66. package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
  67. package/skills/Data Layer/DataStore/SKILL.md +264 -0
  68. package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
  69. package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
  70. package/skills/Data Layer/File Storage/SKILL.md +247 -0
  71. package/skills/Data Layer/Indexing/SKILL.md +184 -0
  72. package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
  73. package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
  74. package/skills/Data Layer/Migration/SKILL.md +243 -0
  75. package/skills/Data Layer/Paging/SKILL.md +264 -0
  76. package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
  77. package/skills/Data Layer/Room/SKILL.md +244 -0
  78. package/skills/Data Layer/SQLite/SKILL.md +255 -0
  79. package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
  80. package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
  81. package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
  82. package/skills/Dependency Injection/Koin/SKILL.md +282 -0
  83. package/skills/Developer Experience/Detekt/SKILL.md +272 -0
  84. package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
  85. package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
  86. package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
  87. package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
  88. package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
  89. package/skills/Media/Audio/SKILL.md +257 -0
  90. package/skills/Media/Camera/SKILL.md +229 -0
  91. package/skills/Media/CameraX/SKILL.md +295 -0
  92. package/skills/Media/ExoPlayer/SKILL.md +258 -0
  93. package/skills/Media/Video/SKILL.md +228 -0
  94. package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
  95. package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
  96. package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
  97. package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
  98. package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
  99. package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
  100. package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
  101. package/skills/Navigation/Navigation/SKILL.md +215 -0
  102. package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
  103. package/skills/Networking/API Contract/SKILL.md +220 -0
  104. package/skills/Networking/Authentication/SKILL.md +210 -0
  105. package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
  106. package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
  107. package/skills/Networking/Ktor/SKILL.md +219 -0
  108. package/skills/Networking/Multipart Upload/SKILL.md +213 -0
  109. package/skills/Networking/OkHttp/SKILL.md +193 -0
  110. package/skills/Networking/REST/SKILL.md +178 -0
  111. package/skills/Networking/Rate Limiting/SKILL.md +170 -0
  112. package/skills/Networking/Retrofit/SKILL.md +241 -0
  113. package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
  114. package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
  115. package/skills/Networking/WebSocket/SKILL.md +224 -0
  116. package/skills/Observability/Crash Reporting/SKILL.md +219 -0
  117. package/skills/Observability/Logging/SKILL.md +168 -0
  118. package/skills/Observability/Metrics/SKILL.md +227 -0
  119. package/skills/Observability/Structured Logging/SKILL.md +234 -0
  120. package/skills/Performance/ANR Prevention/SKILL.md +192 -0
  121. package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
  122. package/skills/Performance/App Startup/SKILL.md +183 -0
  123. package/skills/Performance/Baseline Profile/SKILL.md +205 -0
  124. package/skills/Performance/Battery Optimization/SKILL.md +192 -0
  125. package/skills/Performance/Benchmark/SKILL.md +182 -0
  126. package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
  127. package/skills/Performance/Compose Optimization/SKILL.md +187 -0
  128. package/skills/Performance/Heap Management/SKILL.md +184 -0
  129. package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
  130. package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
  131. package/skills/Performance/Rendering Performance/SKILL.md +205 -0
  132. package/skills/Performance/Startup Optimization/SKILL.md +219 -0
  133. package/skills/Security/Biometric/SKILL.md +224 -0
  134. package/skills/Security/Certificate Transparency/SKILL.md +158 -0
  135. package/skills/Security/Cryptography/SKILL.md +244 -0
  136. package/skills/Security/Encrypted Storage/SKILL.md +273 -0
  137. package/skills/Security/Frida Detection/SKILL.md +230 -0
  138. package/skills/Security/Hook Detection/SKILL.md +197 -0
  139. package/skills/Security/Keystore/SKILL.md +272 -0
  140. package/skills/Security/Network Security Config/SKILL.md +186 -0
  141. package/skills/Security/Obfuscation/SKILL.md +226 -0
  142. package/skills/Security/Proguard/SKILL.md +202 -0
  143. package/skills/Security/R8/SKILL.md +234 -0
  144. package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
  145. package/skills/Security/Root Detection/SKILL.md +220 -0
  146. package/skills/Security/Secure Networking/SKILL.md +220 -0
  147. package/skills/System Integration/AlarmManager/SKILL.md +182 -0
  148. package/skills/System Integration/App Widget/SKILL.md +182 -0
  149. package/skills/System Integration/Deep Link/SKILL.md +187 -0
  150. package/skills/System Integration/Foreground Service/SKILL.md +212 -0
  151. package/skills/System Integration/Notification/SKILL.md +237 -0
  152. package/skills/System Integration/WorkManager/SKILL.md +256 -0
  153. package/skills/System Integration/clipboard/SKILL.md +155 -0
  154. package/skills/System Integration/share-intent/SKILL.md +182 -0
  155. package/skills/Testing/Compose Testing/SKILL.md +296 -0
  156. package/skills/Testing/Espresso/SKILL.md +292 -0
  157. package/skills/Testing/Fake Data/SKILL.md +245 -0
  158. package/skills/Testing/Integration Testing/SKILL.md +288 -0
  159. package/skills/Testing/Mocking/SKILL.md +229 -0
  160. package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
  161. package/skills/Testing/UI Testing/SKILL.md +293 -0
  162. package/skills/Testing/Unit Testing/SKILL.md +309 -0
  163. package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
  164. package/skills/UI System/Compose/SKILL.md +296 -0
  165. package/skills/UI System/Compose Animation/SKILL.md +281 -0
  166. package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
  167. package/skills/UI System/Compose Navigation/SKILL.md +255 -0
  168. package/skills/UI System/Compose Performance/SKILL.md +274 -0
  169. package/skills/UI System/Design System/SKILL.md +217 -0
  170. package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
  171. package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
  172. package/skills/UI System/Loading Strategy/SKILL.md +254 -0
  173. package/skills/UI System/Material 3/SKILL.md +279 -0
  174. package/skills/UI System/RTL/SKILL.md +179 -0
  175. package/src/index.ts +182 -0
  176. package/tsconfig.json +19 -0
@@ -0,0 +1,268 @@
1
+ ---
2
+ name: sync-engine
3
+ description: >
4
+ Data synchronization engine design for Android offline-first apps.
5
+ Load this skill when designing how local data syncs with a remote server,
6
+ handling bidirectional sync, managing sync state, or scheduling background sync.
7
+ ---
8
+
9
+ # Sync Engine
10
+
11
+ ## Overview
12
+ A sync engine coordinates the flow of data between local storage (Room) and a remote server. In offline-first apps, local data is always the source of truth for the UI — the sync engine ensures local and remote stay consistent. It handles connectivity awareness, retry logic, conflict resolution, and sync state tracking.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - **Local first, sync second** — UI reads from Room, sync runs in background
19
+ - Sync is **idempotent** — running it twice produces the same result
20
+ - Track sync state explicitly — show sync status in UI where relevant
21
+ - Use **WorkManager** for background sync — survives process death and reboots
22
+ - Handle conflicts explicitly — don't silently overwrite data
23
+
24
+ ---
25
+
26
+ ## Sync Architecture
27
+
28
+ ```
29
+ UI → ViewModel → Repository (Room) ← Sync Engine → Remote API
30
+
31
+ [Source of Truth]
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Sync State Tracking
37
+
38
+ ```kotlin
39
+ // ✅ Track sync state per entity or globally
40
+ enum class SyncStatus {
41
+ IDLE,
42
+ SYNCING,
43
+ SUCCESS,
44
+ FAILED
45
+ }
46
+
47
+ data class SyncState(
48
+ val status: SyncStatus = SyncStatus.IDLE,
49
+ val lastSyncTime: Instant? = null,
50
+ val error: String? = null
51
+ )
52
+
53
+ // ✅ Persist sync metadata
54
+ @Entity(tableName = "sync_metadata")
55
+ data class SyncMetadataEntity(
56
+ @PrimaryKey val entityType: String, // "users", "orders", etc.
57
+ val lastSyncTime: Long,
58
+ val lastSyncSuccess: Boolean,
59
+ val pendingChanges: Int = 0
60
+ )
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Sync Engine Implementation
66
+
67
+ ```kotlin
68
+ class UserSyncEngine @Inject constructor(
69
+ private val userApi: UserApi,
70
+ private val userDao: UserDao,
71
+ private val syncMetadataDao: SyncMetadataDao,
72
+ private val mapper: UserMapper,
73
+ private val clock: Clock = Clock.systemUTC()
74
+ ) {
75
+ companion object {
76
+ const val ENTITY_TYPE = "users"
77
+ }
78
+
79
+ // ✅ Pull sync — fetch remote, update local
80
+ suspend fun syncFromRemote(): SyncResult {
81
+ return try {
82
+ val lastSync = syncMetadataDao.getLastSyncTime(ENTITY_TYPE)
83
+ val remoteUsers = if (lastSync != null) {
84
+ userApi.getUsersModifiedSince(lastSync) // delta sync
85
+ } else {
86
+ userApi.getAllUsers() // full sync on first run
87
+ }
88
+
89
+ userDao.upsertAll(remoteUsers.map(mapper::toEntity))
90
+
91
+ val deletedIds = userApi.getDeletedSince(lastSync)
92
+ userDao.deleteByIds(deletedIds)
93
+
94
+ syncMetadataDao.updateSyncTime(ENTITY_TYPE, clock.instant().toEpochMilli())
95
+ SyncResult.Success(remoteUsers.size)
96
+ } catch (e: IOException) {
97
+ SyncResult.NetworkError(e)
98
+ } catch (e: Exception) {
99
+ SyncResult.UnknownError(e)
100
+ }
101
+ }
102
+
103
+ // ✅ Push sync — send local changes to remote
104
+ suspend fun syncToRemote(): SyncResult {
105
+ return try {
106
+ val pendingChanges = userDao.getPendingSync()
107
+
108
+ pendingChanges.forEach { entity ->
109
+ when (entity.syncState) {
110
+ SyncState.CREATED -> userApi.createUser(mapper.toDto(entity))
111
+ SyncState.UPDATED -> userApi.updateUser(entity.id, mapper.toDto(entity))
112
+ SyncState.DELETED -> userApi.deleteUser(entity.id)
113
+ }
114
+ userDao.markSynced(entity.id)
115
+ }
116
+
117
+ SyncResult.Success(pendingChanges.size)
118
+ } catch (e: Exception) {
119
+ SyncResult.UnknownError(e)
120
+ }
121
+ }
122
+ }
123
+
124
+ sealed class SyncResult {
125
+ data class Success(val count: Int) : SyncResult()
126
+ data class NetworkError(val cause: IOException) : SyncResult()
127
+ data class UnknownError(val cause: Exception) : SyncResult()
128
+ }
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Tracking Local Changes
134
+
135
+ ```kotlin
136
+ // ✅ Add sync state column to entity
137
+ @Entity(tableName = "users")
138
+ data class UserEntity(
139
+ @PrimaryKey val id: String,
140
+ val name: String,
141
+ val email: String,
142
+ @ColumnInfo(name = "sync_state") val syncState: String = "SYNCED"
143
+ )
144
+
145
+ enum class SyncState { SYNCED, CREATED, UPDATED, DELETED }
146
+
147
+ // ✅ Mark as pending on local write
148
+ @Dao
149
+ interface UserDao {
150
+ @Query("UPDATE users SET sync_state = 'UPDATED' WHERE id = :id")
151
+ suspend fun markPendingUpdate(id: String)
152
+
153
+ @Query("UPDATE users SET sync_state = 'DELETED' WHERE id = :id")
154
+ suspend fun markPendingDelete(id: String)
155
+
156
+ @Query("SELECT * FROM users WHERE sync_state != 'SYNCED'")
157
+ suspend fun getPendingSync(): List<UserEntity>
158
+
159
+ @Query("UPDATE users SET sync_state = 'SYNCED' WHERE id = :id")
160
+ suspend fun markSynced(id: String)
161
+ }
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Background Sync with WorkManager
167
+
168
+ ```kotlin
169
+ // ✅ Periodic background sync
170
+ class SyncWorker(
171
+ context: Context,
172
+ params: WorkerParameters
173
+ ) : CoroutineWorker(context, params) {
174
+
175
+ @Inject lateinit var syncEngine: UserSyncEngine
176
+
177
+ override suspend fun doWork(): Result {
178
+ return try {
179
+ syncEngine.syncFromRemote()
180
+ syncEngine.syncToRemote()
181
+ Result.success()
182
+ } catch (e: Exception) {
183
+ if (runAttemptCount < 3) Result.retry() else Result.failure()
184
+ }
185
+ }
186
+ }
187
+
188
+ // ✅ Schedule periodic sync
189
+ fun schedulePeriodic(context: Context) {
190
+ WorkManager.getInstance(context).enqueueUniquePeriodicWork(
191
+ "periodic_sync",
192
+ ExistingPeriodicWorkPolicy.KEEP,
193
+ PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
194
+ .setConstraints(
195
+ Constraints.Builder()
196
+ .setRequiredNetworkType(NetworkType.CONNECTED)
197
+ .build()
198
+ )
199
+ .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
200
+ .build()
201
+ )
202
+ }
203
+
204
+ // ✅ Trigger immediate sync on app foreground
205
+ fun scheduleImmediateSync(context: Context) {
206
+ WorkManager.getInstance(context).enqueueUniqueWork(
207
+ "immediate_sync",
208
+ ExistingWorkPolicy.REPLACE,
209
+ OneTimeWorkRequestBuilder<SyncWorker>()
210
+ .setConstraints(
211
+ Constraints.Builder()
212
+ .setRequiredNetworkType(NetworkType.CONNECTED)
213
+ .build()
214
+ )
215
+ .build()
216
+ )
217
+ }
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Connectivity-Aware Sync
223
+
224
+ ```kotlin
225
+ // ✅ Observe connectivity and trigger sync when online
226
+ class ConnectivitySyncTrigger @Inject constructor(
227
+ private val context: Context,
228
+ private val workManager: WorkManager
229
+ ) {
230
+ fun observe(): Flow<Boolean> = callbackFlow {
231
+ val cm = context.getSystemService(ConnectivityManager::class.java)
232
+ val callback = object : ConnectivityManager.NetworkCallback() {
233
+ override fun onAvailable(network: Network) {
234
+ trySend(true)
235
+ workManager.enqueueUniqueWork(
236
+ "connectivity_sync",
237
+ ExistingWorkPolicy.REPLACE,
238
+ OneTimeWorkRequestBuilder<SyncWorker>().build()
239
+ )
240
+ }
241
+ override fun onLost(network: Network) { trySend(false) }
242
+ }
243
+ cm.registerDefaultNetworkCallback(callback)
244
+ awaitClose { cm.unregisterNetworkCallback(callback) }
245
+ }
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Anti-Patterns
252
+
253
+ - Syncing on the main thread — causes ANR
254
+ - No retry logic — transient network errors permanently break sync
255
+ - Overwriting local changes with remote on every sync — data loss
256
+ - No sync state tracking — UI can't show sync status or errors
257
+ - Not handling delete propagation — deleted items reappear after sync
258
+ - Full sync every time — use delta sync (modified_since) for large datasets
259
+
260
+ ---
261
+
262
+ ## Related Skills
263
+ - `conflict-resolution` — handling data conflicts during sync
264
+ - `merge-strategy` — merging local and remote changes
265
+ - `workmanager` — durable background sync scheduling
266
+ - `room` — local data source for offline-first
267
+ - `offline-first` — full offline-first architecture
268
+ - `repository-pattern` — sync engine integration in repository
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: dagger
3
+ description: >
4
+ Dagger 2 dependency injection for Android without Hilt.
5
+ Load this skill when working on a project that uses raw Dagger (not Hilt),
6
+ understanding Hilt's internals, building custom components/subcomponents,
7
+ or migrating from Dagger to Hilt.
8
+ ---
9
+
10
+ # Dagger 2
11
+
12
+ ## Overview
13
+ Dagger 2 is a compile-time DI framework that generates Java code for dependency injection. Hilt is built on top of Dagger and covers most Android use cases. Use raw Dagger when you need custom component hierarchies, non-standard scopes, or are working on a project that predates Hilt.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Dagger generates all DI code at **compile time** — no reflection
20
+ - **Components** are the bridge between the object graph and the consumer
21
+ - **Modules** provide dependencies the constructor can't supply
22
+ - **Subcomponents** inherit the parent's bindings and add their own scope
23
+ - Prefer Hilt for new Android projects — raw Dagger only when needed
24
+
25
+ ---
26
+
27
+ ## Basic Setup
28
+
29
+ ```toml
30
+ [versions]
31
+ dagger = "2.51.1"
32
+
33
+ [libraries]
34
+ dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
35
+ dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
36
+ ```
37
+
38
+ ```kotlin
39
+ dependencies {
40
+ implementation(libs.dagger)
41
+ ksp(libs.dagger.compiler)
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Component
48
+
49
+ ```kotlin
50
+ // ✅ Application-level component
51
+ @Singleton
52
+ @Component(modules = [
53
+ NetworkModule::class,
54
+ DatabaseModule::class,
55
+ RepositoryModule::class
56
+ ])
57
+ interface AppComponent {
58
+
59
+ // Expose for injection into Application
60
+ fun inject(app: MyApplication)
61
+
62
+ // Factory — preferred over Builder for constructor params
63
+ @Component.Factory
64
+ interface Factory {
65
+ fun create(@BindsInstance @ApplicationContext context: Context): AppComponent
66
+ }
67
+ }
68
+
69
+ // ✅ Initialize in Application
70
+ class MyApplication : Application() {
71
+ val appComponent: AppComponent by lazy {
72
+ DaggerAppComponent.factory().create(this)
73
+ }
74
+
75
+ override fun onCreate() {
76
+ super.onCreate()
77
+ appComponent.inject(this)
78
+ }
79
+ }
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Modules
85
+
86
+ ```kotlin
87
+ // ✅ @Module — provides dependencies
88
+ @Module
89
+ object NetworkModule {
90
+
91
+ @Provides
92
+ @Singleton
93
+ fun provideOkHttpClient(): OkHttpClient =
94
+ OkHttpClient.Builder().build()
95
+
96
+ @Provides
97
+ @Singleton
98
+ fun provideRetrofit(client: OkHttpClient): Retrofit =
99
+ Retrofit.Builder()
100
+ .baseUrl("https://api.example.com/")
101
+ .client(client)
102
+ .build()
103
+
104
+ @Provides
105
+ @Singleton
106
+ fun provideUserApi(retrofit: Retrofit): UserApi =
107
+ retrofit.create(UserApi::class.java)
108
+ }
109
+
110
+ // ✅ @Binds — for interface → implementation binding (abstract module)
111
+ @Module
112
+ abstract class RepositoryModule {
113
+
114
+ @Binds
115
+ @Singleton
116
+ abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
117
+ }
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Scopes
123
+
124
+ ```kotlin
125
+ // ✅ Define custom scopes
126
+ @Scope
127
+ @Retention(AnnotationRetention.RUNTIME)
128
+ annotation class ActivityScope
129
+
130
+ @Scope
131
+ @Retention(AnnotationRetention.RUNTIME)
132
+ annotation class FragmentScope
133
+
134
+ // ✅ Use on component and provided dependency
135
+ @ActivityScope
136
+ @Subcomponent(modules = [ActivityModule::class])
137
+ interface ActivityComponent {
138
+ fun inject(activity: MainActivity)
139
+
140
+ @Subcomponent.Factory
141
+ interface Factory {
142
+ fun create(): ActivityComponent
143
+ }
144
+ }
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Subcomponents
150
+
151
+ ```kotlin
152
+ // ✅ Subcomponent inherits parent bindings, adds its own scope
153
+ @ActivityScope
154
+ @Subcomponent(modules = [ActivityModule::class])
155
+ interface ActivityComponent {
156
+ fun inject(activity: MainActivity)
157
+
158
+ @Subcomponent.Factory
159
+ interface Factory {
160
+ fun create(): ActivityComponent
161
+ }
162
+ }
163
+
164
+ // ✅ Register subcomponent in parent
165
+ @Module(subcomponents = [ActivityComponent::class])
166
+ object AppSubcomponents
167
+
168
+ // ✅ Create subcomponent from parent
169
+ class MainActivity : AppCompatActivity() {
170
+ private lateinit var activityComponent: ActivityComponent
171
+
172
+ override fun onCreate(savedInstanceState: Bundle?) {
173
+ activityComponent = (application as MyApplication)
174
+ .appComponent
175
+ .activityComponentFactory()
176
+ .create()
177
+ activityComponent.inject(this)
178
+ super.onCreate(savedInstanceState)
179
+ }
180
+ }
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Constructor Injection
186
+
187
+ ```kotlin
188
+ // ✅ Same as Hilt — @Inject on constructor
189
+ class UserRepository @Inject constructor(
190
+ private val userDao: UserDao,
191
+ private val userApi: UserApi
192
+ )
193
+
194
+ class UserMapper @Inject constructor()
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Qualifiers
200
+
201
+ ```kotlin
202
+ // ✅ Distinguish multiple bindings of the same type
203
+ @Qualifier
204
+ @Retention(AnnotationRetention.BINARY)
205
+ annotation class BaseUrl
206
+
207
+ @Module
208
+ object NetworkModule {
209
+
210
+ @Provides
211
+ @Singleton
212
+ @BaseUrl
213
+ fun provideBaseUrl(): String = "https://api.example.com/"
214
+
215
+ @Provides
216
+ @Singleton
217
+ fun provideRetrofit(@BaseUrl baseUrl: String): Retrofit =
218
+ Retrofit.Builder().baseUrl(baseUrl).build()
219
+ }
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Lazy and Provider Injection
225
+
226
+ ```kotlin
227
+ // ✅ Lazy<T> — defer initialization until first use
228
+ class HeavyFeature @Inject constructor(
229
+ private val heavyDep: Lazy<HeavyDependency>
230
+ ) {
231
+ fun use() {
232
+ heavyDep.get().doWork() // initialized on first call
233
+ }
234
+ }
235
+
236
+ // ✅ Provider<T> — get a new instance each time
237
+ class RequestFactory @Inject constructor(
238
+ private val requestProvider: Provider<NetworkRequest>
239
+ ) {
240
+ fun createRequest(): NetworkRequest = requestProvider.get()
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Migration to Hilt
247
+
248
+ ```kotlin
249
+ // Hilt replaces most Dagger boilerplate:
250
+
251
+ // Dagger → Hilt equivalents
252
+ @Component(modules = [...])
253
+ interface AppComponent → @HiltAndroidApp on Application
254
+
255
+ @ActivityScope @Subcomponent(...)
256
+ interface ActivityComponent → @AndroidEntryPoint on Activity
257
+
258
+ appComponent.inject(this) → Removed (automatic)
259
+
260
+ @Component.Factory / @Component.Builder → Removed (Hilt manages)
261
+
262
+ // Keep raw Dagger when:
263
+ // - Custom component hierarchy beyond what Hilt provides
264
+ // - Non-Android modules (pure Kotlin/Java libraries)
265
+ // - Existing codebase that's too large to migrate at once
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Anti-Patterns
271
+
272
+ - Field injection in non-Android classes — use constructor injection
273
+ - Creating components outside of Application — breaks the object graph
274
+ - Providing mutable singletons — hidden shared state causes bugs
275
+ - Deep subcomponent hierarchies — prefer Hilt's flat component model
276
+ - Not using `@Binds` for interface bindings — `@Provides` works but is less efficient
277
+
278
+ ---
279
+
280
+ ## Related Skills
281
+ - `hilt` — Hilt (recommended for Android)
282
+ - `koin` — alternative runtime DI
283
+ - `annotation-processing` — KSP for Dagger code generation