# The app-wide R8 rules for a SoulStream release APK — the ones that belong # to no single plugin. # # This file lives in the repo on purpose. The Gradle project that consumes it, # src-tauri/gen/android/app, is GENERATED and gitignored, and # `tauri android init` rewrites it, so a rule written into that project's own # proguard-rules.pro is a rule with a short life. # `bash src-tauri/android/build.sh --release` copies this file next to that # project's build.gradle.kts, whose release build type reads # # proguardFiles(*fileTree(".") { include("**/*.pro") } # .plus(getDefaultProguardFile("proguard-android-optimize.txt")) ...) # # — anything ending in .pro in that directory. Copying it is a no-op for the # debug build: the debug build type sets isMinifyEnabled = false and names no # proguard files at all, so the path the deploy pipeline runs every twenty # minutes never reads a line of this. # # NOR are the rules for the wry/JNI bridge here. wry's build script writes # proguard-wry.pro next to the Kotlin it generates, in # app/src/main/java/com/soulstream/app/generated/, and the release build type's # **/*.pro glob is recursive, so it is already picked up: Rust's native # methods, WryActivity, Ipc's @JavascriptInterface, RustWebView.evalScript. # proguard-tauri.pro, beside this file, keeps TauriActivity.getPluginManager(). # Duplicating either here would be a second place to get them wrong. # # Per-plugin rules are NOT here. Each plugin carries its own # consumer-rules.pro inside crates/tauri-plugin-*/android, so they travel with # the plugin into a regenerated gen/android and into a plain # `npx tauri android build` too. # # NOTHING BELOW HAS BEEN PROVEN BY A BUILD. Every APK this project has ever # made is assembleArm64Debug with minification off. See ANDROID.md → # "The release build". # Tauri reads its own annotations off the class files at RUNTIME: # PluginHandle.indexMethods() asks each Method whether @Command, # @ActivityCallback and @PermissionCallback are present, and all three are # @Retention(AnnotationRetention.RUNTIME). proguard-android-optimize.txt is # expected to keep them with `-keepattributes *Annotation*`, but that file is # extracted from the Android Gradle plugin when a release build runs and no # release build has ever run here, so it has never existed in this tree to # read. Say it outright rather than inherit it from a file this project does # not own and cannot see. Signature, InnerClasses # and EnclosingMethod are for Jackson, which resolves an @InvokeArg field's # declared type before it fills it. -keepattributes RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations,AnnotationDefault,Signature,InnerClasses,EnclosingMethod # THE GAP. Tauri's own consumer rule is # # -keep @app.tauri.annotation.TauriPlugin public class * { # @app.tauri.annotation.Command public ; ... } # # and a class-member specification matches the members a matched class # DECLARES. These four @Command methods are declared on app.tauri.plugin.Plugin # — the abstract base every plugin extends — which carries no @TauriPlugin of # its own; tauri's other rule for that package keeps only @JniMethod and # native members. So no rule in the build names them, while # PluginHandle.indexMethods() walks the superclass chain with # getDeclaredMethods() and registers them by name regardless. # # registerListener is the one this app rides on. addPluginListener() in # src/mobile/media.svelte.js and src/mobile/xfernote.svelte.js invokes # plugin:media-session|registerListener and # plugin:transfer-notice|registerListener, and those subscriptions are how the # lock-screen card's prev/play/next/stop and the download notice's cancel and # open get back into the app. Lose them and everything still looks right and # nothing either of those buttons does works. # # Written as a precaution, not as a diagnosed bug: whether R8 reaches # inherited members through tauri's rule could not be settled from source, and # it cannot be settled on this machine at all. Six lines to stop asking. -keep class app.tauri.plugin.Plugin { public void registerListener(app.tauri.plugin.Invoke); public void removeListener(app.tauri.plugin.Invoke); public void checkPermissions(app.tauri.plugin.Invoke); public void requestPermissions(app.tauri.plugin.Invoke); } # jackson-databind 2.15.3 — tauri's own dependency, the thing that fills every # @InvokeArg — ships no META-INF/proguard rules of its own, and its # databind/ext/Java7SupportImpl references java.beans.ConstructorProperties and # java.beans.Transient, neither of which exists on Android. R8 in AGP 7+ turns # a missing class into a BUILD ERROR, so without these two lines the release # build may not get as far as producing an APK. # # If R8 names others, its own list is the answer: add what # app/build/outputs/mapping/arm64Release/missing_rules.txt says to this file # and run again. (jackson-core 2.15.3 scanned clean, and the # java.lang.reflect.RecordComponent in jdk14/JDK14Util is a reflective string # rather than a class reference, so it should not be reported.) -dontwarn java.beans.ConstructorProperties -dontwarn java.beans.Transient