# SPDX-FileCopyrightText: 2026 Sulkta-Coop # SPDX-License-Identifier: GPL-3.0-or-later # # R8 keep rules for the Straw app module. The legacy `app/proguard-rules.pro` # is for the upstream NewPipe module — different namespaces, different # rules. This file is OURS. # # AGP's getDefaultProguardFile("proguard-android-optimize.txt") handles # the Android framework + AndroidX + Compose runtime defaults via # consumer rules shipped with each library. We only need to spell out # what those defaults can't see: # # * UniFFI bindings — reflective FFI dispatch from generated code. # * JNA — reflects on every class extending com.sun.jna.Library # (that's how the loadLibrary glue works). # * Our kotlinx-serialization @Serializable types — their generated # $$serializer companions get tree-shaken without explicit keeps. # * Media3 session metadata Parcelables. # -- UniFFI ------------------------------------------------------------- # Generated bindings live under uniffi.strawcore.*. The Rust side calls # them via JNI symbol name; if R8 renames the class or methods, every # extractor call NPEs. -keep class uniffi.strawcore.** { *; } -keep class uniffi.** { *; } # -- JNA --------------------------------------------------------------- # JNA looks up Library subclasses by Class.forName + reflection at # load time. Anything that extends Library or has @FieldOrder must # survive. -keep class * extends com.sun.jna.Library { *; } -keep class com.sun.jna.** { *; } -dontwarn com.sun.jna.** # -- kotlinx-serialization --------------------------------------------- # Every @Serializable type gets a synthetic Companion + $$serializer # class. R8 will strip the $$serializer if nothing visibly calls it # (the lookup goes through reflection on the Companion). -keepattributes *Annotation*, InnerClasses -dontwarn kotlinx.serialization.** -keep,includedescriptorclasses class com.sulkta.straw.**$$serializer { *; } -keepclassmembers class com.sulkta.straw.** { *** Companion; } -keepclasseswithmembers class com.sulkta.straw.** { kotlinx.serialization.KSerializer serializer(...); } # Same dance for our top-level @Serializable types defined outside # `com.sulkta.straw.**` (Rust DTOs, etc.). Belt + suspenders. -keepclassmembers @kotlinx.serialization.Serializable class * { static **$Companion Companion; public static <1>$Companion Companion; } -keepclasseswithmembers @kotlinx.serialization.Serializable class * { kotlinx.serialization.KSerializer serializer(...); } -keep class **$$serializer { *; } # -- Media3 / ExoPlayer ------------------------------------------------ # Most of Media3 ships consumer rules but session-related Parcelables # are reflectively reconstructed across process boundaries (the # MediaController talks to PlaybackService via Binder). Keep their # field names. -keep class androidx.media3.session.** { *; } -keep class androidx.media3.common.MediaItem { *; } -keep class androidx.media3.common.MediaItem$* { *; } -keep class androidx.media3.common.MediaMetadata { *; } # -- Strawcore exceptions / DTOs reflected by UniFFI -------------------- # StrawcoreError is a sealed Throwable hierarchy exposed via UniFFI. # Keep all subclasses + their fields so the Kotlin pattern-match works # after minification. -keep class com.sulkta.straw.feature.player.** { *; } # -- Reflection-via-Class.forName paths from Compose -------------------- # Compose's runtime does some Class.forName for its own bootstrap; the # AGP consumer rules cover this, but documenting the dependency here # so a future bump doesn't surprise us. -keep class androidx.compose.runtime.** { *; } # -- WorkManager Worker classes ---------------------------------------- # WorkManager instantiates Worker subclasses by class name via # reflection (`Class.forName(workerSpec.workerClassName)`). If R8 # renames our UpdateCheckWorker the scheduler enqueues it but the # instantiation fails silently and no checks ever run. -keep class com.sulkta.straw.feature.update.UpdateCheckWorker { *; } -keep class com.sulkta.straw.feature.feed.FeedRefreshWorker { *; } -keep class * extends androidx.work.ListenableWorker { *; }