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,281 @@
1
+ ---
2
+ name: analytics
3
+ description: >
4
+ Firebase Analytics setup and event tracking for Android.
5
+ Load this skill when implementing event tracking, screen tracking,
6
+ user properties, conversion funnels, or integrating analytics
7
+ with the app's architecture.
8
+ ---
9
+
10
+ # Analytics
11
+
12
+ ## Overview
13
+ Firebase Analytics provides free, unlimited event tracking for Android apps. It automatically tracks some events (first_open, session_start) and allows custom events. Events appear in the Firebase console and can be forwarded to Google Analytics, BigQuery, and Ads.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Analytics must be **disabled in debug builds** — dev events pollute production data
20
+ - Track **meaningful user actions** — not every tap, only business-relevant events
21
+ - Use a **centralized analytics wrapper** — never call Firebase directly from UI
22
+ - Define an **event taxonomy** before implementation — consistent naming is critical
23
+ - User PII (name, email) must **never** be sent as event parameters
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```kotlin
30
+ dependencies {
31
+ implementation(platform(libs.firebase.bom))
32
+ implementation(libs.firebase.analytics)
33
+ }
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Analytics Wrapper
39
+
40
+ ```kotlin
41
+ // ✅ Centralized wrapper — never call FirebaseAnalytics directly from UI/ViewModel
42
+ interface Analytics {
43
+ fun logEvent(event: AnalyticsEvent)
44
+ fun setUserId(userId: String?)
45
+ fun setUserProperty(name: String, value: String?)
46
+ fun logScreenView(screenName: String, screenClass: String)
47
+ }
48
+
49
+ class FirebaseAnalyticsImpl @Inject constructor(
50
+ @ApplicationContext context: Context
51
+ ) : Analytics {
52
+
53
+ private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
54
+
55
+ override fun logEvent(event: AnalyticsEvent) {
56
+ firebaseAnalytics.logEvent(event.name, event.toBundle())
57
+ }
58
+
59
+ override fun setUserId(userId: String?) {
60
+ firebaseAnalytics.setUserId(userId)
61
+ }
62
+
63
+ override fun setUserProperty(name: String, value: String?) {
64
+ firebaseAnalytics.setUserProperty(name, value)
65
+ }
66
+
67
+ override fun logScreenView(screenName: String, screenClass: String) {
68
+ firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW) {
69
+ param(FirebaseAnalytics.Param.SCREEN_NAME, screenName)
70
+ param(FirebaseAnalytics.Param.SCREEN_CLASS, screenClass)
71
+ }
72
+ }
73
+ }
74
+
75
+ // ✅ No-op implementation for debug builds
76
+ class NoOpAnalytics @Inject constructor() : Analytics {
77
+ override fun logEvent(event: AnalyticsEvent) = Unit
78
+ override fun setUserId(userId: String?) = Unit
79
+ override fun setUserProperty(name: String, value: String?) = Unit
80
+ override fun logScreenView(screenName: String, screenClass: String) = Unit
81
+ }
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Event Taxonomy
87
+
88
+ ```kotlin
89
+ // ✅ Sealed class for type-safe event definitions
90
+ sealed class AnalyticsEvent(val name: String) {
91
+
92
+ abstract fun toBundle(): Bundle
93
+
94
+ // Auth events
95
+ object Login : AnalyticsEvent("login") {
96
+ override fun toBundle() = bundleOf(
97
+ FirebaseAnalytics.Param.METHOD to "email"
98
+ )
99
+ }
100
+
101
+ object Logout : AnalyticsEvent("logout") {
102
+ override fun toBundle() = Bundle.EMPTY
103
+ }
104
+
105
+ data class SignUp(val method: String) : AnalyticsEvent("sign_up") {
106
+ override fun toBundle() = bundleOf(
107
+ FirebaseAnalytics.Param.METHOD to method
108
+ )
109
+ }
110
+
111
+ // Content events
112
+ data class ViewItem(val itemId: String, val itemName: String, val category: String)
113
+ : AnalyticsEvent(FirebaseAnalytics.Event.VIEW_ITEM) {
114
+ override fun toBundle() = bundleOf(
115
+ FirebaseAnalytics.Param.ITEM_ID to itemId,
116
+ FirebaseAnalytics.Param.ITEM_NAME to itemName,
117
+ FirebaseAnalytics.Param.ITEM_CATEGORY to category
118
+ )
119
+ }
120
+
121
+ data class Search(val query: String) : AnalyticsEvent(FirebaseAnalytics.Event.SEARCH) {
122
+ override fun toBundle() = bundleOf(
123
+ FirebaseAnalytics.Param.SEARCH_TERM to query
124
+ )
125
+ }
126
+
127
+ // Error events
128
+ data class ErrorOccurred(val errorType: String, val errorMessage: String)
129
+ : AnalyticsEvent("error_occurred") {
130
+ override fun toBundle() = bundleOf(
131
+ "error_type" to errorType,
132
+ "error_message" to errorMessage.take(100) // max 100 chars
133
+ )
134
+ }
135
+
136
+ // Feature usage
137
+ data class FeatureUsed(val featureName: String) : AnalyticsEvent("feature_used") {
138
+ override fun toBundle() = bundleOf("feature_name" to featureName)
139
+ }
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Usage in ViewModel
146
+
147
+ ```kotlin
148
+ // ✅ Log events from ViewModel — not from Compose/UI
149
+ @HiltViewModel
150
+ class ProductViewModel @Inject constructor(
151
+ private val repository: ProductRepository,
152
+ private val analytics: Analytics
153
+ ) : ViewModel() {
154
+
155
+ fun onProductViewed(product: Product) {
156
+ analytics.logEvent(
157
+ AnalyticsEvent.ViewItem(
158
+ itemId = product.id,
159
+ itemName = product.name,
160
+ category = product.category
161
+ )
162
+ )
163
+ }
164
+
165
+ fun onSearchPerformed(query: String) {
166
+ analytics.logEvent(AnalyticsEvent.Search(query))
167
+ }
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Screen Tracking
174
+
175
+ ```kotlin
176
+ // ✅ Track screen views automatically via Navigation
177
+ @Composable
178
+ fun AppNavHost(navController: NavHostController, analytics: Analytics) {
179
+
180
+ val currentEntry by navController.currentBackStackEntryAsState()
181
+
182
+ LaunchedEffect(currentEntry) {
183
+ currentEntry?.destination?.route?.let { route ->
184
+ analytics.logScreenView(
185
+ screenName = route,
186
+ screenClass = route
187
+ )
188
+ }
189
+ }
190
+
191
+ NavHost(navController, startDestination = HomeRoute) {
192
+ // routes...
193
+ }
194
+ }
195
+ ```
196
+
197
+ ---
198
+
199
+ ## User Properties
200
+
201
+ ```kotlin
202
+ // ✅ Set stable user attributes for segmentation
203
+ class UserAnalyticsManager @Inject constructor(private val analytics: Analytics) {
204
+
205
+ fun onUserLoggedIn(user: User) {
206
+ analytics.setUserId(user.id)
207
+ analytics.setUserProperty("account_type", user.accountType)
208
+ analytics.setUserProperty("subscription_plan", user.plan)
209
+ // ❌ Never set PII
210
+ // analytics.setUserProperty("email", user.email) // WRONG
211
+ }
212
+
213
+ fun onUserLoggedOut() {
214
+ analytics.setUserId(null)
215
+ }
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Hilt Binding by Build Type
222
+
223
+ ```kotlin
224
+ // ✅ Inject NoOp in debug, real impl in release
225
+ @Module
226
+ @InstallIn(SingletonComponent::class)
227
+ abstract class AnalyticsModule {
228
+
229
+ @Binds
230
+ @Singleton
231
+ abstract fun bindAnalytics(
232
+ // Switch based on build type
233
+ impl: FirebaseAnalyticsImpl // or NoOpAnalytics in debug flavor
234
+ ): Analytics
235
+ }
236
+
237
+ // ✅ Better — use BuildConfig
238
+ @Module
239
+ @InstallIn(SingletonComponent::class)
240
+ object AnalyticsModule {
241
+
242
+ @Provides
243
+ @Singleton
244
+ fun provideAnalytics(@ApplicationContext context: Context): Analytics =
245
+ if (BuildConfig.DEBUG) NoOpAnalytics()
246
+ else FirebaseAnalyticsImpl(context)
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Event Naming Rules
253
+
254
+ ```
255
+ ✅ snake_case — user_signed_up, product_viewed, checkout_started
256
+ ✅ Max 40 characters for event name
257
+ ✅ Max 25 parameters per event
258
+ ✅ Max 100 characters for parameter value (strings)
259
+ ❌ No spaces, no special characters except underscore
260
+ ❌ No reserved prefixes: firebase_, google_, ga_
261
+ ❌ No PII in any parameter
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Anti-Patterns
267
+
268
+ - Calling `FirebaseAnalytics` directly from Composable — not testable, hard to disable
269
+ - Logging analytics in debug builds — pollutes production dashboards
270
+ - Sending PII (email, name, phone) as event parameters — compliance violation
271
+ - Tracking every user interaction — noise, hard to find signal
272
+ - Inconsistent event names (`user_login` vs `login_user` vs `userLogin`) — breaks funnels
273
+ - No event taxonomy document — events drift over time, become meaningless
274
+
275
+ ---
276
+
277
+ ## Related Skills
278
+ - `firebase` — Firebase core setup
279
+ - `crashlytics` — crash reporting alongside analytics
280
+ - `remote-config` — feature flags informed by analytics
281
+ - `side-effect-management` — analytics as a side effect in ViewModel
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: crashlytics
3
+ description: >
4
+ Firebase Crashlytics setup and usage for Android crash reporting.
5
+ Load this skill when configuring Crashlytics, logging custom events,
6
+ adding user context to crash reports, or handling non-fatal errors.
7
+ ---
8
+
9
+ # Crashlytics
10
+
11
+ ## Overview
12
+ Firebase Crashlytics is a real-time crash reporter that helps track, prioritize, and fix stability issues. It automatically captures fatal crashes and provides detailed stack traces, device info, and custom context. Non-fatal errors can also be reported manually.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - **Disable** Crashlytics in debug builds — don't pollute production data with dev crashes
19
+ - Add **user context** before crashes happen — userId, screen, and key attributes help diagnose
20
+ - Report **non-fatal errors** explicitly — caught exceptions that indicate problems
21
+ - Use **custom keys** to add state context — what the user was doing before the crash
22
+ - Always pair Crashlytics with **proper logging** — crash reports alone miss context
23
+
24
+ ---
25
+
26
+ ## Setup
27
+
28
+ ```kotlin
29
+ // build.gradle.kts (app)
30
+ plugins {
31
+ alias(libs.plugins.firebase.crashlytics)
32
+ }
33
+
34
+ dependencies {
35
+ implementation(platform(libs.firebase.bom))
36
+ implementation(libs.firebase.crashlytics)
37
+ }
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Enable / Disable by Build Type
43
+
44
+ ```kotlin
45
+ // ✅ Disable in debug — only report in release
46
+ class MyApplication : Application() {
47
+ override fun onCreate() {
48
+ super.onCreate()
49
+ FirebaseCrashlytics.getInstance()
50
+ .setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
51
+ }
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## User Context
58
+
59
+ ```kotlin
60
+ // ✅ Set user identity — helps group crashes by user
61
+ class CrashlyticsUserTracker @Inject constructor() {
62
+
63
+ fun setUser(userId: String, email: String?) {
64
+ FirebaseCrashlytics.getInstance().apply {
65
+ setUserId(userId)
66
+ email?.let { setCustomKey("user_email", it) }
67
+ }
68
+ }
69
+
70
+ fun clearUser() {
71
+ FirebaseCrashlytics.getInstance().apply {
72
+ setUserId("")
73
+ setCustomKey("user_email", "")
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Custom Keys — State Context
82
+
83
+ ```kotlin
84
+ // ✅ Log app state before a crash
85
+ class CrashlyticsContext @Inject constructor() {
86
+
87
+ fun setScreen(screenName: String) {
88
+ FirebaseCrashlytics.getInstance()
89
+ .setCustomKey("current_screen", screenName)
90
+ }
91
+
92
+ fun setFeatureFlag(key: String, value: Boolean) {
93
+ FirebaseCrashlytics.getInstance()
94
+ .setCustomKey("flag_$key", value)
95
+ }
96
+
97
+ fun setApiEndpoint(endpoint: String) {
98
+ FirebaseCrashlytics.getInstance()
99
+ .setCustomKey("last_api_endpoint", endpoint)
100
+ }
101
+
102
+ fun setDatabaseVersion(version: Int) {
103
+ FirebaseCrashlytics.getInstance()
104
+ .setCustomKey("db_version", version)
105
+ }
106
+ }
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Breadcrumb Logging
112
+
113
+ ```kotlin
114
+ // ✅ Log events leading up to a crash
115
+ class CrashlyticsLogger @Inject constructor() {
116
+
117
+ fun log(message: String) {
118
+ FirebaseCrashlytics.getInstance().log(message)
119
+ }
120
+
121
+ fun logUserAction(action: String) {
122
+ FirebaseCrashlytics.getInstance().log("USER_ACTION: $action")
123
+ }
124
+
125
+ fun logNetworkCall(endpoint: String, statusCode: Int) {
126
+ FirebaseCrashlytics.getInstance()
127
+ .log("NETWORK: $endpoint -> $statusCode")
128
+ }
129
+ }
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Non-Fatal Error Reporting
135
+
136
+ ```kotlin
137
+ // ✅ Report caught exceptions that indicate a problem
138
+ class UserRepository @Inject constructor(
139
+ private val crashlytics: CrashlyticsLogger
140
+ ) {
141
+ suspend fun getUser(id: String): Result<User> {
142
+ return try {
143
+ val user = api.getUser(id)
144
+ Result.success(user.toDomain())
145
+ } catch (e: HttpException) {
146
+ if (e.code() == 500) {
147
+ // ✅ Server errors are worth tracking
148
+ FirebaseCrashlytics.getInstance().recordException(e)
149
+ }
150
+ Result.failure(e)
151
+ } catch (e: Exception) {
152
+ // ✅ Unexpected exceptions always reported
153
+ FirebaseCrashlytics.getInstance().recordException(e)
154
+ Result.failure(e)
155
+ }
156
+ }
157
+ }
158
+
159
+ // ✅ In global error handler
160
+ class GlobalExceptionHandler @Inject constructor() {
161
+
162
+ fun report(throwable: Throwable, context: String) {
163
+ FirebaseCrashlytics.getInstance().apply {
164
+ setCustomKey("error_context", context)
165
+ recordException(throwable)
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Integration with Timber
174
+
175
+ ```kotlin
176
+ // ✅ Route Timber ERROR logs to Crashlytics
177
+ class CrashlyticsTree : Timber.Tree() {
178
+ override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
179
+ if (priority < Log.ERROR) return
180
+
181
+ FirebaseCrashlytics.getInstance().apply {
182
+ tag?.let { setCustomKey("log_tag", it) }
183
+ log(message)
184
+ t?.let { recordException(it) }
185
+ }
186
+ }
187
+ }
188
+
189
+ // Plant in Application
190
+ class MyApplication : Application() {
191
+ override fun onCreate() {
192
+ super.onCreate()
193
+ if (BuildConfig.DEBUG) {
194
+ Timber.plant(Timber.DebugTree())
195
+ } else {
196
+ Timber.plant(CrashlyticsTree())
197
+ }
198
+ }
199
+ }
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Testing Crashes
205
+
206
+ ```kotlin
207
+ // ✅ Force a test crash (debug only)
208
+ if (BuildConfig.DEBUG) {
209
+ Button(onClick = {
210
+ FirebaseCrashlytics.getInstance().log("Test crash triggered")
211
+ throw RuntimeException("Test crash")
212
+ }) {
213
+ Text("Test Crash")
214
+ }
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Anti-Patterns
221
+
222
+ - Enabling Crashlytics in debug builds — pollutes crash data with dev noise
223
+ - No user context — impossible to reproduce user-specific crashes
224
+ - Reporting every caught exception — noise drowns out real issues; be selective
225
+ - No custom keys — crash report without state context is hard to diagnose
226
+ - Not logging breadcrumbs — no trail of events leading to the crash
227
+
228
+ ---
229
+
230
+ ## Related Skills
231
+ - `firebase` — Firebase core setup
232
+ - `analytics` — event tracking alongside crash reporting
233
+ - `logging` — structured logging complementing Crashlytics
234
+ - `error-handling` — error handling policy across layers
@@ -0,0 +1,200 @@
1
+ ---
2
+ name: firebase
3
+ description: >
4
+ Firebase setup and core configuration for Android.
5
+ Load this skill when initializing Firebase, configuring google-services.json,
6
+ setting up multiple Firebase environments (dev/prod), or integrating Firebase
7
+ into a multi-module project.
8
+ ---
9
+
10
+ # Firebase
11
+
12
+ ## Overview
13
+ Firebase is Google's app development platform providing backend services — authentication, messaging, crash reporting, analytics, remote config, and more. Each service is a separate SDK added independently. The core setup is shared across all Firebase services.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - One `google-services.json` per app variant — dev and prod must use separate Firebase projects
20
+ - Initialize Firebase **once** in `Application.onCreate()` — never in Activity or Fragment
21
+ - Use **separate Firebase projects** for debug and release — never mix environments
22
+ - Add only the Firebase SDKs you actually use — each adds APK size and startup overhead
23
+ - Never commit `google-services.json` with production credentials to public repos
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```toml
30
+ [versions]
31
+ firebase-bom = "33.5.1"
32
+ google-services = "4.4.2"
33
+
34
+ [libraries]
35
+ firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
36
+ # Individual SDKs — version managed by BOM
37
+ firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" }
38
+ firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" }
39
+ firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }
40
+ firebase-auth = { module = "com.google.firebase:firebase-auth-ktx" }
41
+ firebase-config = { module = "com.google.firebase:firebase-config-ktx" }
42
+
43
+ [plugins]
44
+ google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
45
+ firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.2" }
46
+ ```
47
+
48
+ ```kotlin
49
+ // build.gradle.kts (root)
50
+ plugins {
51
+ alias(libs.plugins.google.services) apply false
52
+ alias(libs.plugins.firebase.crashlytics) apply false
53
+ }
54
+
55
+ // build.gradle.kts (app)
56
+ plugins {
57
+ alias(libs.plugins.google.services)
58
+ alias(libs.plugins.firebase.crashlytics)
59
+ }
60
+
61
+ dependencies {
62
+ implementation(platform(libs.firebase.bom)) // ✅ BOM manages all versions
63
+ implementation(libs.firebase.analytics)
64
+ implementation(libs.firebase.crashlytics)
65
+ implementation(libs.firebase.messaging)
66
+ }
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Application Setup
72
+
73
+ ```kotlin
74
+ // ✅ Firebase auto-initializes via ContentProvider — no manual init needed
75
+ // FirebaseApp.initializeApp() is called automatically
76
+
77
+ @HiltAndroidApp
78
+ class MyApplication : Application() {
79
+ override fun onCreate() {
80
+ super.onCreate()
81
+ // Firebase is already initialized here
82
+ // Configure per-service settings if needed
83
+ }
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Multiple Environments (Dev / Prod)
90
+
91
+ ```
92
+ // ✅ Separate google-services.json per build variant
93
+ app/
94
+ ├── src/
95
+ │ ├── debug/
96
+ │ │ └── google-services.json ← dev Firebase project
97
+ │ └── release/
98
+ │ └── google-services.json ← prod Firebase project
99
+ ```
100
+
101
+ ```kotlin
102
+ // ✅ Or configure via build flavors
103
+ android {
104
+ flavorDimensions += "environment"
105
+ productFlavors {
106
+ create("dev") {
107
+ dimension = "environment"
108
+ applicationIdSuffix = ".dev"
109
+ }
110
+ create("prod") {
111
+ dimension = "environment"
112
+ }
113
+ }
114
+ }
115
+
116
+ // Files:
117
+ // app/src/dev/google-services.json
118
+ // app/src/prod/google-services.json
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Manual Firebase App Initialization (Multi-Module / KMP)
124
+
125
+ ```kotlin
126
+ // ✅ When automatic initialization isn't sufficient
127
+ val options = FirebaseOptions.Builder()
128
+ .setApiKey(BuildConfig.FIREBASE_API_KEY)
129
+ .setApplicationId(BuildConfig.FIREBASE_APP_ID)
130
+ .setProjectId(BuildConfig.FIREBASE_PROJECT_ID)
131
+ .build()
132
+
133
+ FirebaseApp.initializeApp(context, options, "secondary")
134
+ val secondaryApp = Firebase.app("secondary")
135
+ val secondaryDb = Firebase.database(secondaryApp)
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Hilt Integration
141
+
142
+ ```kotlin
143
+ // ✅ Provide Firebase services via Hilt
144
+ @Module
145
+ @InstallIn(SingletonComponent::class)
146
+ object FirebaseModule {
147
+
148
+ @Provides
149
+ @Singleton
150
+ fun provideFirebaseAnalytics(): FirebaseAnalytics =
151
+ FirebaseAnalytics.getInstance(get()) // or inject context
152
+
153
+ @Provides
154
+ @Singleton
155
+ fun provideFirebaseRemoteConfig(): FirebaseRemoteConfig =
156
+ FirebaseRemoteConfig.getInstance().also { config ->
157
+ config.setConfigSettingsAsync(
158
+ remoteConfigSettings {
159
+ minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) 0 else 3600
160
+ }
161
+ )
162
+ }
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Disable Firebase in Debug
169
+
170
+ ```kotlin
171
+ // ✅ Disable analytics and crashlytics in debug builds
172
+ class MyApplication : Application() {
173
+ override fun onCreate() {
174
+ super.onCreate()
175
+ if (BuildConfig.DEBUG) {
176
+ FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false)
177
+ FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false)
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Anti-Patterns
186
+
187
+ - Single Firebase project for dev and prod — production data polluted with test events
188
+ - Committing `google-services.json` with prod keys to public repo — security risk
189
+ - Initializing Firebase in Activity — causes multiple initializations
190
+ - Adding all Firebase SDKs without using them — increases APK size and startup time
191
+ - Not using BOM — version conflicts between Firebase SDKs
192
+
193
+ ---
194
+
195
+ ## Related Skills
196
+ - `firebase-messaging` — push notifications with FCM
197
+ - `crashlytics` — crash reporting setup
198
+ - `analytics` — event tracking
199
+ - `remote-config` — feature flags from Firebase
200
+ - `firebase-auth` — authentication (not in current skill list — add if needed)