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,179 @@
1
+ ---
2
+ name: allocation-optimization
3
+ description: >
4
+ Reducing object allocations and GC pressure in Android.
5
+ Load this skill when optimizing hot code paths, reducing garbage
6
+ collection pauses, minimizing allocations in draw/layout loops,
7
+ or improving frame rate by reducing allocation churn.
8
+ ---
9
+
10
+ # Allocation Optimization
11
+
12
+ ## Overview
13
+ Excessive object allocation causes frequent garbage collection pauses, which manifest as frame drops and janky animations. On Android, the ART GC is generational and mostly concurrent, but large or frequent allocations in hot code paths (draw loops, scroll, animation) still cause measurable pauses.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - **Never allocate** in `onDraw`, `Canvas` operations, or tight animation loops
20
+ - Reuse objects with object pools or `remember {}` in Compose
21
+ - Prefer **primitives** over boxed types (`Int` not `Integer`, `IntArray` not `List<Int>`)
22
+ - Use `StringBuilder` for string concatenation in loops — not `+` operator
23
+ - Profile with **Android Studio Profiler → Memory → Allocation** before optimizing
24
+
25
+ ---
26
+
27
+ ## Common Allocation Hotspots
28
+
29
+ ```kotlin
30
+ // ❌ Allocating in draw loop — every frame creates new objects
31
+ class CustomView(context: Context) : View(context) {
32
+ override fun onDraw(canvas: Canvas) {
33
+ val paint = Paint() // allocation every frame ❌
34
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat()) // allocation every frame ❌
35
+ canvas.drawRect(rect, paint)
36
+ }
37
+ }
38
+
39
+ // ✅ Pre-allocate outside draw loop
40
+ class CustomView(context: Context) : View(context) {
41
+ private val paint = Paint().apply { color = Color.RED }
42
+ private val rect = RectF()
43
+
44
+ override fun onDraw(canvas: Canvas) {
45
+ rect.set(0f, 0f, width.toFloat(), height.toFloat()) // reuse — no allocation
46
+ canvas.drawRect(rect, paint)
47
+ }
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## String Concatenation in Loops
54
+
55
+ ```kotlin
56
+ // ❌ String concatenation creates new String each iteration
57
+ var result = ""
58
+ items.forEach { result += it.name + ", " } // O(n²) allocations
59
+
60
+ // ✅ StringBuilder — single allocation
61
+ val sb = StringBuilder()
62
+ items.forEach { sb.append(it.name).append(", ") }
63
+ val result = sb.toString()
64
+
65
+ // ✅ Or use joinToString — optimized internally
66
+ val result = items.joinToString(", ") { it.name }
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Avoiding Boxing
72
+
73
+ ```kotlin
74
+ // ❌ Boxing primitives in hot path
75
+ val counts: Map<String, Int> = mutableMapOf() // Int boxed to Integer
76
+
77
+ // ✅ Use SparseArray for Int keys — avoids boxing
78
+ val counts = SparseIntArray()
79
+
80
+ // ✅ Use primitive arrays
81
+ val buffer = IntArray(1024) // no boxing
82
+ val floatBuffer = FloatArray(256)
83
+
84
+ // ❌ forEach on ranges — can box index
85
+ for (i in 0..100) { ... } // optimized by compiler, actually fine
86
+
87
+ // ❌ Lambda capturing primitives
88
+ listOf(1, 2, 3).map { it * 2 } // boxes Int in some cases
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Compose Allocation Optimization
94
+
95
+ ```kotlin
96
+ // ❌ Creating lambda on every recomposition
97
+ @Composable
98
+ fun UserList(users: List<User>, onUserClick: (User) -> Unit) {
99
+ users.forEach { user ->
100
+ UserItem(
101
+ user = user,
102
+ onClick = { onUserClick(user) } // ❌ new lambda every recomposition
103
+ )
104
+ }
105
+ }
106
+
107
+ // ✅ Use remember or stable callbacks
108
+ @Composable
109
+ fun UserList(users: List<User>, onUserClick: (User) -> Unit) {
110
+ users.forEach { user ->
111
+ val onClick = remember(user.id) { { onUserClick(user) } }
112
+ UserItem(user = user, onClick = onClick)
113
+ }
114
+ }
115
+
116
+ // ❌ Creating objects in composable body
117
+ @Composable
118
+ fun Chart(data: List<Float>) {
119
+ val path = Path() // ❌ recreated every recomposition
120
+ }
121
+
122
+ // ✅ remember to reuse
123
+ @Composable
124
+ fun Chart(data: List<Float>) {
125
+ val path = remember { Path() } // ✅ created once
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Reusable Buffers
132
+
133
+ ```kotlin
134
+ // ✅ Thread-local buffer for repeated operations
135
+ private val threadLocalBuffer = ThreadLocal.withInitial { ByteArray(8192) }
136
+
137
+ fun processData(input: InputStream) {
138
+ val buffer = threadLocalBuffer.get()!!
139
+ var read: Int
140
+ while (input.read(buffer).also { read = it } != -1) {
141
+ process(buffer, read)
142
+ }
143
+ }
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Measuring Allocations
149
+
150
+ ```
151
+ Android Studio Profiler → Memory tab:
152
+ 1. Start recording allocations
153
+ 2. Perform the action to profile (scroll, animation)
154
+ 3. Stop recording
155
+ 4. Sort by "Alloc Count" — find hotspots
156
+
157
+ Key signals:
158
+ - Many small allocations in RecyclerView/LazyColumn scroll → reuse objects
159
+ - Repeated allocation of same type → use pool or remember
160
+ - Allocation inside animation frame → move outside animation
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Anti-Patterns
166
+
167
+ - Allocating `Paint`, `Path`, `RectF` inside `onDraw` — every frame creates garbage
168
+ - String `+` concatenation in loops — use `StringBuilder`
169
+ - Creating collections inside tight loops — pre-allocate or reuse
170
+ - `List<Int>` when `IntArray` would work — unnecessary boxing
171
+ - Allocating large arrays on the main thread — use background thread
172
+
173
+ ---
174
+
175
+ ## Related Skills
176
+ - `heap-management` — managing heap size and cache limits
177
+ - `compose-optimization` — Compose-specific allocation patterns
178
+ - `rendering-performance` — frame rendering and draw optimization
179
+ - `benchmark` — measuring allocation count with benchmarks
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: app-startup
3
+ description: >
4
+ Jetpack App Startup library for initializer management in Android.
5
+ Load this skill when controlling SDK initialization order, lazy-loading
6
+ initializers, replacing ContentProvider-based auto-init, or reducing
7
+ the number of ContentProviders at startup.
8
+ ---
9
+
10
+ # App Startup
11
+
12
+ ## Overview
13
+ The Jetpack App Startup library provides a standard way to initialize components at app startup. It consolidates multiple `ContentProvider` initializers (used by many SDKs) into a single one, reducing startup overhead. It also supports lazy initialization and explicit dependency ordering between initializers.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Use App Startup to **consolidate** multiple SDK ContentProviders into one
20
+ - Define **dependencies** between initializers to control order
21
+ - Use **lazy initialization** for SDKs not needed immediately
22
+ - Disable auto-init for SDKs that have their own ContentProvider when using App Startup
23
+ - Keep each `Initializer.create()` fast — it runs on the main thread during startup
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```toml
30
+ # libs.versions.toml
31
+ [libraries]
32
+ androidx-startup = { module = "androidx.startup:startup-runtime", version = "1.1.1" }
33
+ ```
34
+
35
+ ```kotlin
36
+ // build.gradle.kts
37
+ dependencies {
38
+ implementation(libs.androidx.startup)
39
+ }
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Creating Initializers
45
+
46
+ ```kotlin
47
+ // ✅ Timber initializer
48
+ class TimberInitializer : Initializer<Unit> {
49
+ override fun create(context: Context) {
50
+ if (BuildConfig.DEBUG) {
51
+ Timber.plant(Timber.DebugTree())
52
+ }
53
+ }
54
+
55
+ override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
56
+ }
57
+
58
+ // ✅ Analytics initializer — depends on Timber being initialized first
59
+ class AnalyticsInitializer : Initializer<AnalyticsClient> {
60
+ override fun create(context: Context): AnalyticsClient {
61
+ return AnalyticsClient.initialize(context).also {
62
+ Timber.d("Analytics initialized")
63
+ }
64
+ }
65
+
66
+ override fun dependencies(): List<Class<out Initializer<*>>> =
67
+ listOf(TimberInitializer::class.java) // ✅ Timber initializes first
68
+ }
69
+
70
+ // ✅ WorkManager initializer
71
+ class WorkManagerInitializer : Initializer<WorkManager> {
72
+ override fun create(context: Context): WorkManager {
73
+ val config = Configuration.Builder()
74
+ .setMinimumLoggingLevel(Log.INFO)
75
+ .build()
76
+ WorkManager.initialize(context, config)
77
+ return WorkManager.getInstance(context)
78
+ }
79
+
80
+ override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
81
+ }
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Manifest Registration
87
+
88
+ ```xml
89
+ <!-- AndroidManifest.xml -->
90
+ <provider
91
+ android:name="androidx.startup.InitializationProvider"
92
+ android:authorities="${applicationId}.androidx-startup"
93
+ android:exported="false">
94
+
95
+ <!-- Register initializers -->
96
+ <meta-data
97
+ android:name="com.example.TimberInitializer"
98
+ android:value="androidx.startup" />
99
+
100
+ <meta-data
101
+ android:name="com.example.AnalyticsInitializer"
102
+ android:value="androidx.startup" />
103
+
104
+ <meta-data
105
+ android:name="com.example.WorkManagerInitializer"
106
+ android:value="androidx.startup" />
107
+ </provider>
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Lazy Initialization
113
+
114
+ ```kotlin
115
+ // ✅ Initialize on demand — not at startup
116
+ class HeavySdkInitializer : Initializer<HeavySdk> {
117
+ override fun create(context: Context): HeavySdk {
118
+ return HeavySdk.initialize(context)
119
+ }
120
+ override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
121
+ }
122
+
123
+ // ✅ Disable auto-init in manifest — initialize manually when needed
124
+ // In manifest:
125
+ // <meta-data android:name="com.example.HeavySdkInitializer" android:value="androidx.startup" />
126
+ // Remove this entry to disable auto-init
127
+
128
+ // Initialize manually when first needed
129
+ AppInitializer.getInstance(context)
130
+ .initializeComponent(HeavySdkInitializer::class.java)
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Disabling Third-Party SDK Auto-Init
136
+
137
+ ```xml
138
+ <!-- ✅ Disable WorkManager's own ContentProvider to avoid duplicate init -->
139
+ <provider
140
+ android:name="androidx.work.impl.WorkManagerInitializer"
141
+ android:authorities="${applicationId}.workmanager-init"
142
+ android:exported="false"
143
+ tools:node="remove" />
144
+
145
+ <!-- ✅ Disable Firebase auto-init if using App Startup instead -->
146
+ <provider
147
+ android:name="com.google.firebase.provider.FirebaseInitProvider"
148
+ android:authorities="${applicationId}.firebaseinitprovider"
149
+ tools:node="remove" />
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Measuring Startup Impact
155
+
156
+ ```kotlin
157
+ // ✅ Use systrace to see initializer timing
158
+ // In Initializer.create():
159
+ Trace.beginSection("TimberInitializer")
160
+ try {
161
+ Timber.plant(Timber.DebugTree())
162
+ } finally {
163
+ Trace.endSection()
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Anti-Patterns
170
+
171
+ - Doing network calls inside `Initializer.create()` — runs on main thread
172
+ - Not declaring dependencies between initializers — ordering not guaranteed
173
+ - Registering all SDKs eagerly when most can be lazy — slows startup
174
+ - Initializing inside `Application.onCreate()` AND via App Startup — double initialization
175
+ - Ignoring `tools:node="remove"` for SDKs with their own ContentProviders — duplicate init
176
+
177
+ ---
178
+
179
+ ## Related Skills
180
+ - `startup-optimization` — broader startup performance strategy
181
+ - `baseline-profile` — pre-compiling initialization code paths
182
+ - `workmanager` — WorkManager initialization via App Startup
183
+ - `lifecycle` — deferring init beyond startup using lifecycle observers
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: baseline-profile
3
+ description: >
4
+ Baseline Profiles for ahead-of-time compilation in Android.
5
+ Load this skill when generating baseline profiles, reducing app
6
+ startup time, improving scroll jank on first run, or integrating
7
+ profile generation into the CI pipeline.
8
+ ---
9
+
10
+ # Baseline Profile
11
+
12
+ ## Overview
13
+ Baseline Profiles tell the Android Runtime (ART) which code paths to compile ahead-of-time (AOT) during app install. Without a profile, ART uses JIT compilation, which is slower on first run. With a baseline profile, critical code paths (startup, scroll, navigation) are pre-compiled, resulting in faster startup and smoother initial interactions.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Generate profiles for **critical user journeys** — startup, main screen scroll, key flows
20
+ - Profile generation requires a **physical device or emulator with API 28+**
21
+ - Profiles must be **regenerated** after major code changes
22
+ - Combine with **Macrobenchmark** to measure the improvement
23
+ - Ship profiles in the release build — they're included in the APK/AAB automatically
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```toml
30
+ # libs.versions.toml
31
+ [versions]
32
+ macrobenchmark = "1.3.0"
33
+ profileinstaller = "1.3.1"
34
+
35
+ [libraries]
36
+ androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "profileinstaller" }
37
+ androidx-benchmark-macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "macrobenchmark" }
38
+ ```
39
+
40
+ ```kotlin
41
+ // app/build.gradle.kts
42
+ dependencies {
43
+ implementation(libs.androidx.profileinstaller)
44
+ }
45
+
46
+ // macrobenchmark/build.gradle.kts (separate module)
47
+ plugins {
48
+ alias(libs.plugins.android.test)
49
+ }
50
+ android {
51
+ targetProjectPath = ":app"
52
+ experimentalProperties["android.experimental.self-instrumenting"] = true
53
+ }
54
+ dependencies {
55
+ implementation(libs.androidx.benchmark.macro)
56
+ }
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Profile Generator
62
+
63
+ ```kotlin
64
+ // macrobenchmark module
65
+ @RunWith(AndroidJUnit4::class)
66
+ class BaselineProfileGenerator {
67
+
68
+ @get:Rule
69
+ val rule = BaselineProfileRule()
70
+
71
+ @Test
72
+ fun generate() = rule.collect(
73
+ packageName = "com.example.app",
74
+ profileBlock = {
75
+ // ✅ Cover critical user journeys
76
+
77
+ // 1. App startup
78
+ startActivityAndWait()
79
+
80
+ // 2. Navigate to main screen
81
+ device.findObject(By.text("Home")).click()
82
+ device.waitForIdle()
83
+
84
+ // 3. Scroll through a list
85
+ val list = device.findObject(By.scrollable(true))
86
+ list.fling(Direction.DOWN)
87
+ list.fling(Direction.UP)
88
+ device.waitForIdle()
89
+
90
+ // 4. Open a detail screen
91
+ device.findObject(By.text("First Item")).click()
92
+ device.waitForIdle()
93
+ }
94
+ )
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Generate and Install Profile
101
+
102
+ ```bash
103
+ # Generate the profile
104
+ ./gradlew :macrobenchmark:connectedAndroidTest \
105
+ -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
106
+
107
+ # Profile is saved to:
108
+ # app/src/main/baseline-prof.txt (automatically)
109
+ # or manually copy from device:
110
+ # adb pull /sdcard/Android/media/com.example.app/baseline-prof.txt app/src/main/
111
+
112
+ # Verify profile is included in release build
113
+ ./gradlew :app:assembleRelease
114
+ # Check APK contains assets/dexopt/baseline.prof
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Manual Profile (Simple)
120
+
121
+ ```
122
+ # app/src/main/baseline-prof.txt
123
+ # List critical class and method patterns
124
+
125
+ # Startup classes
126
+ Lcom/example/app/MainActivity;
127
+ Lcom/example/app/di/AppModule;
128
+
129
+ # Compose runtime
130
+ Landroidx/compose/runtime/Composer;->**
131
+ Landroidx/compose/ui/platform/AndroidComposeView;->**
132
+
133
+ # Key repository
134
+ Lcom/example/app/data/UserRepository;->getUser(Ljava/lang/String;)**
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Measuring Impact
140
+
141
+ ```kotlin
142
+ // ✅ Measure startup with and without baseline profile
143
+ @RunWith(AndroidJUnit4::class)
144
+ class StartupBenchmark {
145
+ @get:Rule
146
+ val benchmarkRule = MacrobenchmarkRule()
147
+
148
+ @Test
149
+ fun startupWithBaselineProfile() = benchmarkRule.measureRepeated(
150
+ packageName = "com.example.app",
151
+ metrics = listOf(StartupTimingMetric()),
152
+ compilationMode = CompilationMode.Partial(
153
+ baselineProfileMode = BaselineProfileMode.Require // ✅ must use profile
154
+ ),
155
+ startupMode = StartupMode.COLD,
156
+ iterations = 5
157
+ ) {
158
+ pressHome()
159
+ startActivityAndWait()
160
+ }
161
+
162
+ @Test
163
+ fun startupWithoutProfile() = benchmarkRule.measureRepeated(
164
+ packageName = "com.example.app",
165
+ metrics = listOf(StartupTimingMetric()),
166
+ compilationMode = CompilationMode.None, // no AOT — baseline comparison
167
+ startupMode = StartupMode.COLD,
168
+ iterations = 5
169
+ ) {
170
+ pressHome()
171
+ startActivityAndWait()
172
+ }
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## CI Integration
179
+
180
+ ```yaml
181
+ # .github/workflows/baseline-profile.yml
182
+ - name: Generate Baseline Profile
183
+ run: |
184
+ ./gradlew :macrobenchmark:connectedAndroidTest \
185
+ -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
186
+ # Commit updated baseline-prof.txt to repo
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Anti-Patterns
192
+
193
+ - Not regenerating profiles after significant code changes — stale profile misses new code paths
194
+ - Generating on emulator only — physical device gives more representative profiles
195
+ - Not measuring improvement — can't justify the maintenance cost without data
196
+ - Including only startup in profile generation — also cover scroll and navigation
197
+ - Shipping without `profileinstaller` dependency — profile won't be installed at app install time
198
+
199
+ ---
200
+
201
+ ## Related Skills
202
+ - `macrobenchmark` — measuring startup and runtime with Macrobenchmark
203
+ - `startup-optimization` — complementary startup improvements
204
+ - `benchmark` — microbenchmark for method-level measurement
205
+ - `app-startup` — App Startup library for initialization ordering