straw/strawApp/proguard-rules.pro
Kayos ccd24c4ed3 vc=55: in-app auto-updater polling fdroid.sulkta.com
WorkManager periodic worker hits the repo's index-v2.json, parses
the highest versionCode for our package, compares with
BuildConfig.VERSION_CODE. When newer: posts a notification with
ACTION_VIEW on the APK URL — Android's DownloadManager picks it up
and the system installer takes over. No INSTALL_PACKAGES perm
needed.

Settings:
- Check for updates toggle (default on — closing NewPipe's silent
  staleness gap is the explicit motivation)
- Interval picker (1h / 6h / 24h, default 6h — WorkManager has a
  15-min periodic floor anyway)
- Last-checked timestamp + 'update available' tag when caught-up
  state is dirty
- Check now button — runs the same path as the worker so behaviors
  stay identical

Cold start fires one check too so users see pending updates without
waiting a full interval.

R8 keep-rule for UpdateCheckWorker added — WorkManager instantiates
workers by name via reflection.
2026-05-26 09:40:07 -07:00

89 lines
4 KiB
Prolog

# 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 * extends androidx.work.ListenableWorker { *; }