From 6bbdf845d85ced66bb173e2bf9d312be2a8f3f76 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sun, 30 Aug 2026 14:02:20 -0400 Subject: [PATCH 1/2] perf(r8): drop the protobuf and gRPC server keep rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `-keep class * extends GeneratedMessageLite { *; }` and its $Builder twin pinned 29,633 items — 94% of the app's entire keep radius — and blocked R8 from optimizing 24,909 methods, 81% of every method it was forbidden to touch. Both are replaced by a field-only rule that now ships inside com.flipcash:{ocp,flipcash2}-client-protocol, where the generated messages live. javalite resolves fields reflectively and reaches builders and message methods from ordinary call sites, so the methods never needed keeping. `-keep class * implements io.grpc.BindableService { *; }` goes with them. All 45 matches were *ImplBase and *CoroutineImplBase server skeletons generated alongside the client stubs; nothing in an Android client implements a gRPC service, and no other rule kept them, so R8 can now delete them outright. Measured by the R8 configuration analyzer, before and after: live methods 230,686 -> 205,144 (-25,542) live classes 42,338 -> 41,770 (-568) live fields 96,939 -> 95,692 (-1,247) obfuscation score 89.0% -> 96.1% optimization score 89.3% -> 96.3% shrinking score 89.1% -> 96.1% The AbstractStub rule stays for now. It pins 114 classes with all members and the stubs are reached from generated newStub() factories, so it is very likely removable too, but that one needs a run on a device rather than a static argument. Merges after both contract packages publish the rule; the pinned versions in libs.versions.toml have to carry it first. --- apps/flipcash/app/proguard-rules.pro | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/flipcash/app/proguard-rules.pro b/apps/flipcash/app/proguard-rules.pro index 2d65c81b89..5d907f23cb 100644 --- a/apps/flipcash/app/proguard-rules.pro +++ b/apps/flipcash/app/proguard-rules.pro @@ -10,15 +10,11 @@ -keepnames class com.flipcash.app.core.AppRoute -keepnames class com.flipcash.app.core.AppRoute$** -# Protobuf — keep all generated message classes and their builders. -# Using type-hierarchy rules so new packages / updated gRPC stubs are -# caught automatically instead of listing every gen package. --keep class * extends com.google.protobuf.GeneratedMessageLite { *; } --keep class * extends com.google.protobuf.GeneratedMessageLite$Builder { *; } +# Protobuf keep rules ship with the contract packages themselves, in +# com.flipcash:{ocp,flipcash2}-client-protocol. -# gRPC — keep generated service stubs (abstract + concrete) +# gRPC — keep the generated client stubs -keep class * extends io.grpc.stub.AbstractStub { *; } --keep class * implements io.grpc.BindableService { *; } # Keep our scan classes that interact with native -keep class com.kik.scan.** { *; } From 6d99fedb81f8e46ea571407814cce36a5895cc3f Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sun, 30 Aug 2026 22:10:19 -0400 Subject: [PATCH 2/2] build(deps): take the contract packages at 0.3.0 for their keep rules 0.3.0 is the first release of either package to ship META-INF/proguard/*.pro alongside its generated messages, which is what makes the removal of the app's own protobuf rules in this branch safe. Both jars on Central carry the rule; R8 reads it straight out of the dependency. Pinning the version and dropping the local rules in one change keeps the app from ever sitting on a commit with no protobuf keep rule at all. --- apps/flipcash/app/proguard-rules.pro | 6 ++++-- gradle/libs.versions.toml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/flipcash/app/proguard-rules.pro b/apps/flipcash/app/proguard-rules.pro index b5f5bfec1a..a97a0d11af 100644 --- a/apps/flipcash/app/proguard-rules.pro +++ b/apps/flipcash/app/proguard-rules.pro @@ -7,8 +7,10 @@ -keepnames class com.flipcash.app.core.AppRoute -keepnames class com.flipcash.app.core.AppRoute$** -# Protobuf keep rules ship with the contract packages themselves, in -# com.flipcash:{ocp,flipcash2}-client-protocol. +# Protobuf keep rules ship with the contract packages themselves, from 0.3.0 on: +# com.flipcash:{ocp,flipcash2}-client-protocol carry them in META-INF/proguard/, which +# R8 reads straight out of the jar. Downgrading either pin below 0.3.0 silently removes +# the app's only protobuf keep rule. # gRPC — keep the generated client stubs -keep class * extends io.grpc.stub.AbstractStub { *; } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 31ef5f56f0..c7d8c51558 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -66,8 +66,10 @@ protovalidate-kt = "0.1.1" # Generated client SDKs for the two backend contracts. Separate versions on purpose: the # protos are independent (flipcash2 does not import ocp), so the packages move on their own # cadence and there is nothing to keep aligned. -ocp-client-protocol = "0.2.0" -flipcash2-client-protocol = "0.2.0" +# 0.3.0 is the first release of either package to ship R8 keep rules for its generated +# messages, which is what lets proguard-rules.pro drop its own. +ocp-client-protocol = "0.3.0" +flipcash2-client-protocol = "0.3.0" # The Android port is the ONLY libphonenumber this app depends on, deliberately. Google's # `com.googlecode` artifact used to sit alongside it; the two ship separate copies of the metadata,