Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import com.skydoves.myapplication.models.UnstableUser
* 1. Add @TraceRecomposition annotation to your composable
* 2. Build the project (tracking code is automatically injected by the compiler)
* 3. Enable logging in your Application class:
* LoggerProvider.setEnabled(BuildConfig.DEBUG)
* ComposeStabilityAnalyzer.setEnabled(BuildConfig.DEBUG)
* 4. Run your app and check Logcat for "Recomposition" tag
*/
@Composable
Expand Down Expand Up @@ -252,7 +252,7 @@ fun RecompositionDemo() {
* class MyApp : Application() {
* override fun onCreate() {
* super.onCreate()
* LoggerProvider.setEnabled(BuildConfig.DEBUG)
* ComposeStabilityAnalyzer.setEnabled(BuildConfig.DEBUG)
* }
* }
* ```
Expand Down
13 changes: 13 additions & 0 deletions compose-stability-analyzer-idea/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ All notable changes to the IntelliJ IDEA plugin will be documented in this file.

---

## [0.5.2] - 2025-11-13

### Fixed
- **Fixed APK size increase in release builds** (Issue #39)
- ProGuard rules were keeping entire stability-runtime package unnecessarily
- Optimized consumer-rules.pro to only keep classes used by compiler-injected code
- Now only keeps `RecompositionTracker` methods (constructor, trackParameter, logIfThresholdMet)
- Logger classes only kept if explicitly used via `ComposeStabilityAnalyzer.setLogger()`
- Compile-time classes (`StabilityInfo`, `ComposableInfo`, `ParameterInfo`) now removed by R8
- This fix dramatically reduces release APK size when using the plugin

---

## [0.5.1] - 2025-11-10

### Added
Expand Down
6 changes: 6 additions & 0 deletions compose-stability-analyzer-idea/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ intellijPlatform {
</ul>
""".trimIndent()
changeNotes = """
<b>0.5.2</b>
<ul>
<li><b>CRITICAL FIX: Resolved APK size bloat in release builds</b> (Issue #39)</li>
<li>ProGuard rules optimized - only keeps classes actually used by compiler-injected code</li>
<li>Dramatically reduced release APK size when using the plugin</li>
</ul>
<b>0.5.1</b>
<ul>
<li><b>Added wasmJs target support</b> - Runtime module now supports WebAssembly JavaScript for Compose Multiplatform web apps (Issue #32)</li>
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ kotlin.mpp.androidGradlePluginCompatibility.nowarn=true

# Maven publishing
GROUP=com.github.skydoves
VERSION_NAME=0.5.1
VERSION_NAME=0.5.2

POM_URL=https://github.com/skydoves/compose-stability-analyzer/
POM_SCM_URL=https://github.com/skydoves/compose-stability-analyzer/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin {

// This version should match the version in gradle.properties
// Update this when bumping the library version
private const val VERSION = "0.5.1"
private const val VERSION = "0.5.2"

// Compiler option keys
private const val OPTION_ENABLED = "enabled"
Expand Down
43 changes: 22 additions & 21 deletions stability-runtime/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
# Keep all classes and functions annotated with @TraceRecomposition
# These are transformed by the compiler plugin and must not be obfuscated
-keep @com.skydoves.compose.stability.runtime.TraceRecomposition class * { *; }
-keep class * {
@com.skydoves.compose.stability.runtime.TraceRecomposition *;
}
-keepclassmembers class * {
@com.skydoves.compose.stability.runtime.TraceRecomposition *;
}

# Keep the TraceRecomposition annotation itself
# Keep annotations (used at compile-time, small overhead to keep)
-keep @interface com.skydoves.compose.stability.runtime.TraceRecomposition

# Keep all stability runtime annotations
-keep @interface com.skydoves.compose.stability.runtime.StableForAnalysis
-keep @interface com.skydoves.compose.stability.runtime.SkipStabilityAnalysis
-keep @interface com.skydoves.compose.stability.runtime.IgnoreStabilityReport

# Keep RecompositionTracker and related classes used by injected code
-keep class com.skydoves.compose.stability.runtime.RecompositionTracker { *; }
-keep class com.skydoves.compose.stability.runtime.** { *; }
# Keep ONLY RecompositionTracker - used by compiler-injected code
# The compiler injects calls to: constructor, trackParameter(), logIfThresholdMet()
-keep class com.skydoves.compose.stability.runtime.RecompositionTracker {
public <init>(java.lang.String, java.lang.String, int);
public <methods>;
}

# Keep public API for users who explicitly call ComposeStabilityAnalyzer.setLogger()
# ComposeStabilityAnalyzer is a Kotlin object (singleton), methods are accessed via INSTANCE
# These are only kept if referenced (R8 will remove if unused)
-keep,allowobfuscation class com.skydoves.compose.stability.runtime.ComposeStabilityAnalyzer {
public <methods>;
}
-keep,allowobfuscation interface com.skydoves.compose.stability.runtime.RecompositionLogger {
public <methods>;
}
-keep,allowobfuscation class com.skydoves.compose.stability.runtime.RecompositionEvent { *; }
-keep,allowobfuscation class com.skydoves.compose.stability.runtime.ParameterChange { *; }

# Keep all stability info data classes
-keep class com.skydoves.compose.stability.runtime.StabilityInfo { *; }
-keep class com.skydoves.compose.stability.runtime.ComposableInfo { *; }
-keep class com.skydoves.compose.stability.runtime.ParameterInfo { *; }
# Note: StabilityInfo/ComposableInfo/ParameterInfo are only used for JSON generation
# at compile-time. They don't need to be kept in the runtime APK.
# R8 will automatically remove them if unused.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import kotlin.concurrent.Volatile
* }
*
* // In Application.onCreate()
* LoggerProvider.setLogger(FirebaseRecompositionLogger())
* ComposeStabilityAnalyzer.setLogger(FirebaseRecompositionLogger())
* ```
*/
public interface RecompositionLogger {
Expand Down Expand Up @@ -110,13 +110,13 @@ public expect class DefaultRecompositionLogger() : RecompositionLogger {
* Usage:
* ```kotlin
* // Set custom logger (typically in Application.onCreate() or MainActivity)
* LoggerProvider.setLogger(MyCustomLogger())
* ComposeStabilityAnalyzer.setLogger(MyCustomLogger())
*
* // Enable/disable logging
* LoggerProvider.setEnabled(BuildConfig.DEBUG)
* ComposeStabilityAnalyzer.setEnabled(BuildConfig.DEBUG)
*
* // Get current logger
* val logger = LoggerProvider.getLogger()
* val logger = ComposeStabilityAnalyzer.getLogger()
* ```
*/
public object ComposeStabilityAnalyzer {
Expand Down Expand Up @@ -155,7 +155,7 @@ public object ComposeStabilityAnalyzer {
*
* Use this to disable logging in production builds:
* ```kotlin
* LoggerProvider.setEnabled(BuildConfig.DEBUG)
* ComposeStabilityAnalyzer.setEnabled(BuildConfig.DEBUG)
* ```
*
* @param enabled Whether logging should be enabled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class LoggerProviderTest {
class ComposeStabilityAnalyzerTest {

private val defaultLogger = DefaultRecompositionLogger()

Expand All @@ -40,13 +40,13 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_defaultLogger() {
fun testComposeStabilityAnalyzer_defaultLogger() {
val logger = ComposeStabilityAnalyzer.getLogger()
assertNotNull(logger)
}

@Test
fun testLoggerProvider_setCustomLogger() {
fun testComposeStabilityAnalyzer_setCustomLogger() {
val customLogger = TestLogger()
ComposeStabilityAnalyzer.setLogger(customLogger)

Expand All @@ -55,12 +55,12 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_enabledByDefault() {
fun testComposeStabilityAnalyzer_enabledByDefault() {
assertTrue(ComposeStabilityAnalyzer.isEnabled())
}

@Test
fun testLoggerProvider_setEnabled() {
fun testComposeStabilityAnalyzer_setEnabled() {
ComposeStabilityAnalyzer.setEnabled(false)
assertFalse(ComposeStabilityAnalyzer.isEnabled())

Expand All @@ -69,7 +69,7 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_logEvent_whenEnabled() {
fun testComposeStabilityAnalyzer_logEvent_whenEnabled() {
val customLogger = TestLogger()
ComposeStabilityAnalyzer.setLogger(customLogger)
ComposeStabilityAnalyzer.setEnabled(true)
Expand All @@ -82,7 +82,7 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_logEvent_whenDisabled() {
fun testComposeStabilityAnalyzer_logEvent_whenDisabled() {
val customLogger = TestLogger()
ComposeStabilityAnalyzer.setLogger(customLogger)
ComposeStabilityAnalyzer.setEnabled(false)
Expand All @@ -94,7 +94,7 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_multipleEvents() {
fun testComposeStabilityAnalyzer_multipleEvents() {
val customLogger = TestLogger()
ComposeStabilityAnalyzer.setLogger(customLogger)
ComposeStabilityAnalyzer.setEnabled(true)
Expand All @@ -114,7 +114,7 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_changeLogger_midStream() {
fun testComposeStabilityAnalyzer_changeLogger_midStream() {
val logger1 = TestLogger()
val logger2 = TestLogger()

Expand All @@ -132,7 +132,7 @@ class LoggerProviderTest {
}

@Test
fun testLoggerProvider_toggleEnabled() {
fun testComposeStabilityAnalyzer_toggleEnabled() {
val customLogger = TestLogger()
ComposeStabilityAnalyzer.setLogger(customLogger)

Expand Down