Files
xamarin-neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.Android/proguard.cfg
Trevi Awater fb361f0f4c Obfuscate the Android DEX with R8
Mirrors lojack-connect. .NET for Android runs no DEX shrinker by default, and
even with AndroidLinkTool=r8 the ProGuard config the SDK generates hardcodes
-dontobfuscate -- a flag nothing later in the config list can undo -- so Play
Console's "DEX code optimization" report scores obfuscation at ~1%.

_AndroidObfuscateDex drops the SDK's proguard_xamarin.cfg from R8's --pg-conf
list and substitutes a copy without that line, regenerating the
-printmapping/-keepattributes tail the SDK would have appended (absolute path:
R8 resolves a relative -printmapping against the config file's own directory).
49.8% of DEX classes are now renamed.

proguard.cfg carries the keeps the generated rules miss: classes the .NET
runtime resolves by name from native code (net.dot.android.**), and public and
protected fields, which the trimmer covers for methods only. The target also
caches aapt2's keep rules outside FileWrites -- the SDK adds them to
@(ProguardConfiguration) inside _CreateBaseApkWithAapt2 and registers the file
as a FileWrite, so an incremental Release build that skips the resource link
loses them and ships an APK that dies inflating FitWindowsFrameLayout.

Verified on a Pixel 9 emulator (API 36) with the obfuscated Release APK:
launch, connection list, Add Connection form, and a Bolt connection attempt
that exercises the network/TLS stack and surfaces the driver's error dialog.

The AAB carries mapping.txt, so Play retraces Java stacks itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 22:58:36 +02:00

23 lines
1.2 KiB
INI

# App-level R8 keep rules, on top of the ones .NET for Android generates
# (see proguard_xamarin.cfg and the _AndroidObfuscateDex target in the csproj).
# The .NET runtime resolves this one by name from native code -- no DEX
# reference points at it, so R8 renames it and startup dies with
# "ClassNotFoundException: net.dot.android.ApplicationRegistration".
# The SDK's own config only covers net.dot.jni.** and net.dot.android.crypto.**,
# because upstream never obfuscates.
-keep class net.dot.android.** { *; <init>(...); }
# The trimmer's generated keep rules (proguard_project_references.cfg) cover the
# Java *methods* the bindings call, but not their fields -- upstream never
# obfuscates, so the gap never showed. A bound property backed by a Java field
# reads it through JNI by name, and renaming breaks that:
# NoSuchFieldError: no "Landroidx/lifecycle/Lifecycle$State;" field "DESTROYED"
# NoSuchFieldError: no "I" field "left" in class "Landroidx/core/graphics/Insets;"
# Only the API surface a binding can reach needs it; private fields still get
# renamed, and class names -- what Play's report counts -- are untouched by this.
-keepclassmembers class * {
public <fields>;
protected <fields>;
}