mirror of
https://github.com/awatertrevi/xamarin-neo4j.git
synced 2026-09-22 09:05:29 +00:00
Compare commits
2 Commits
927e7627a6
...
1c319e6619
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c319e6619 | ||
|
|
fb361f0f4c |
30
README.md
30
README.md
@@ -50,6 +50,36 @@ dotnet test Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.Tests/
|
|||||||
dotnet test Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.IntegrationTests/
|
dotnet test Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.IntegrationTests/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Android DEX shrinking & obfuscation (R8)
|
||||||
|
|
||||||
|
Release builds of the Android head run R8 over the Java/DEX side
|
||||||
|
(`AndroidLinkTool=r8` in `Xamarin.Neo4j.Android.csproj`). Play Console's *DEX code
|
||||||
|
optimization* report scores obfuscation at ~1% on a stock .NET MAUI build: .NET for
|
||||||
|
Android runs no DEX shrinker by default, and even with R8 on, the ProGuard config the
|
||||||
|
SDK generates hardcodes `-dontobfuscate` — a flag nothing later in the config list can
|
||||||
|
undo. The `_AndroidObfuscateDex` target therefore drops that file from R8's `--pg-conf`
|
||||||
|
list and substitutes `Xamarin.Neo4j.Android/proguard_xamarin.cfg` (the same file minus
|
||||||
|
that line), plus a generated file carrying the `-printmapping`/`-keepattributes` tail
|
||||||
|
the SDK would have appended. Measured on the Release APK: **49.8% of DEX classes
|
||||||
|
renamed, up from ~0%**.
|
||||||
|
|
||||||
|
Only library-internal classes are renamed: the trimmer emits a `-keep` rule for every
|
||||||
|
Java type the managed bindings reference, aapt2 one for every class named in a layout
|
||||||
|
or the manifest, and each Android Callable Wrapper gets its own.
|
||||||
|
`Xamarin.Neo4j.Android/proguard.cfg` covers what those miss — things resolved by name
|
||||||
|
from native code. Add to it if a Release build dies with `ClassNotFoundException`,
|
||||||
|
`NoSuchFieldError` or `NoSuchMethodError` where a Debug build does not.
|
||||||
|
|
||||||
|
`mapping.txt` is embedded in the AAB
|
||||||
|
(`BUNDLE-METADATA/com.android.tools.build.obfuscation/proguard.map`), so Play Console
|
||||||
|
retraces obfuscated Java stacks by itself. Managed (C#) stack traces are unaffected —
|
||||||
|
R8 only touches DEX.
|
||||||
|
|
||||||
|
Local Release builds must be clean: aapt2's keep rules are registered as a `FileWrite`,
|
||||||
|
so an incremental build that skips the resource link has `IncrementalClean` delete them.
|
||||||
|
The target caches a copy outside `FileWrites` and errors out if even that is missing —
|
||||||
|
delete `Xamarin.Neo4j.Android/obj/Release` if it fires.
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
- .NET MAUI
|
- .NET MAUI
|
||||||
|
|||||||
@@ -53,4 +53,56 @@
|
|||||||
<ProjectReference Include="..\Xamarin.Neo4j\Xamarin.Neo4j.csproj" />
|
<ProjectReference Include="..\Xamarin.Neo4j\Xamarin.Neo4j.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Android Release: shrink and obfuscate the Java/DEX half of the app with
|
||||||
|
R8. .NET for Android runs no DEX shrinker by default, so Play Console's
|
||||||
|
"DEX code optimization" report scores obfuscation at ~1%. The trimmer emits
|
||||||
|
a keep rule for every Java type the managed bindings reference
|
||||||
|
(obj/.../proguard/proguard_project_references.cfg), aapt2 one for every
|
||||||
|
class named in a layout, and each Android Callable Wrapper gets its own,
|
||||||
|
so only library-internal classes are renamed. -->
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<AndroidLinkTool>r8</AndroidLinkTool>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProguardConfiguration Include="proguard.cfg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Swap the SDK's generated proguard_xamarin.cfg (which hardcodes
|
||||||
|
-dontobfuscate, a flag nothing later in the config list can undo) for our
|
||||||
|
copy without it, and regenerate the -printmapping/-keepattributes tail the
|
||||||
|
SDK appends to that same file so crash stacks stay retraceable. -->
|
||||||
|
<Target Name="_AndroidObfuscateDex" AfterTargets="_CalculateProguardConfigurationFiles" Condition="'$(AndroidLinkTool)' == 'r8'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_AndroidObfuscationProguardConfig>$(IntermediateOutputPath)proguard\proguard_obfuscate.cfg</_AndroidObfuscationProguardConfig>
|
||||||
|
<_AndroidAaptProguardRules>$(IntermediateOutputPath)proguard\aapt_rules.cached.txt</_AndroidAaptProguardRules>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<_AndroidObfuscationProguardLines Include="-ignorewarnings" Condition="'$(AndroidR8IgnoreWarnings)' == 'True'" />
|
||||||
|
<_AndroidObfuscationProguardLines Include="-keepattributes SourceFile" />
|
||||||
|
<_AndroidObfuscationProguardLines Include="-keepattributes LineNumberTable" />
|
||||||
|
<!-- Absolute: R8 resolves a relative -printmapping against the directory
|
||||||
|
of the config file that declares it, not the working directory. -->
|
||||||
|
<_AndroidObfuscationProguardLines Include="-printmapping "$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(AndroidProguardMappingFile)'))"" Condition="'$(AndroidProguardMappingFile)' != ''" />
|
||||||
|
</ItemGroup>
|
||||||
|
<MakeDir Directories="$(IntermediateOutputPath)proguard" />
|
||||||
|
<WriteLinesToFile File="$(_AndroidObfuscationProguardConfig)" Lines="@(_AndroidObfuscationProguardLines)" Overwrite="true" WriteOnlyWhenDifferent="true" />
|
||||||
|
<!-- aapt2 derives keep rules for every class named in a layout or the
|
||||||
|
manifest, but 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 both loses the
|
||||||
|
item and has IncrementalClean delete the file, shipping an APK that
|
||||||
|
dies inflating androidx.appcompat.widget.FitWindowsFrameLayout. Keep a
|
||||||
|
copy outside FileWrites and feed R8 that one instead. -->
|
||||||
|
<Copy SourceFiles="$(IntermediateOutputPath)aapt_rules.txt" DestinationFiles="$(_AndroidAaptProguardRules)" SkipUnchangedFiles="true" Condition="Exists('$(IntermediateOutputPath)aapt_rules.txt')" />
|
||||||
|
<Error Condition="!Exists('$(_AndroidAaptProguardRules)')" Text="R8 is enabled but no aapt2 keep rules are available: delete obj\$(Configuration) and publish again to force a full resource link." />
|
||||||
|
<ItemGroup>
|
||||||
|
<_ProguardConfiguration Remove="$(IntermediateOutputPath)proguard\proguard_xamarin.cfg" />
|
||||||
|
<_ProguardConfiguration Remove="$(IntermediateOutputPath)aapt_rules.txt" />
|
||||||
|
<_ProguardConfiguration Include="$(MSBuildProjectDirectory)\proguard_xamarin.cfg" />
|
||||||
|
<_ProguardConfiguration Include="$(_AndroidObfuscationProguardConfig)" />
|
||||||
|
<_ProguardConfiguration Include="$(_AndroidAaptProguardRules)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# 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>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# Verbatim copy of the ProGuard configuration .NET for Android generates at
|
||||||
|
# obj/<Config>/<TFM>/proguard/proguard_xamarin.cfg, minus its hardcoded
|
||||||
|
# "-dontobfuscate". ProGuard has no switch that undoes that flag, so the only
|
||||||
|
# way to let R8 rename DEX classes is to drop the file that sets it from R8's
|
||||||
|
# --pg-conf list and substitute this one (see the _AndroidObfuscateDex target
|
||||||
|
# in the csproj).
|
||||||
|
#
|
||||||
|
# Taken from Microsoft.Android.Sdk 36.1.69 (.NET 10). When the Android SDK pack
|
||||||
|
# is updated, diff this against the generated file after a Release build --
|
||||||
|
# a keep rule added upstream and missed here means a runtime JNI failure.
|
||||||
|
# The trailing -ignorewarnings/-keepattributes/-printmapping lines the SDK
|
||||||
|
# appends to that file are regenerated by the csproj target instead.
|
||||||
|
|
||||||
|
-keep class android.support.multidex.MultiDexApplication { <init>(); }
|
||||||
|
-keep class net.dot.jni.** { *; <init>(); }
|
||||||
|
-keep class mono.MonoRuntimeProvider* { *; <init>(...); }
|
||||||
|
-keep class mono.MonoPackageManager { *; <init>(...); }
|
||||||
|
-keep class mono.MonoPackageManager_Resources { *; <init>(...); }
|
||||||
|
-keep class mono.android.** { *; <init>(...); }
|
||||||
|
-keep class mono.java.** { *; <init>(...); }
|
||||||
|
-keep class mono.javax.** { *; <init>(...); }
|
||||||
|
-keep class net.dot.jni.ManagedPeer { *; <init>(...); }
|
||||||
|
-keep class xamarin.android.net.ServerCertificateCustomValidator_TrustManager { *; <init>(...); }
|
||||||
|
-keep class xamarin.android.net.ServerCertificateCustomValidator_TrustManager_FakeSSLSession { *; <init>(...); }
|
||||||
|
-keep class xamarin.android.net.ServerCertificateCustomValidator_AlwaysAcceptingHostnameVerifier { *; <init>(...); }
|
||||||
|
|
||||||
|
-keep class android.runtime.** { <init>(...); }
|
||||||
|
-keep class assembly_mono_android.android.runtime.** { <init>(...); }
|
||||||
|
# hash for android.runtime and assembly_mono_android.android.runtime.
|
||||||
|
-keep class md52ce486a14f4bcd95899665e9d932190b.** { *; <init>(...); }
|
||||||
|
-keepclassmembers class md52ce486a14f4bcd95899665e9d932190b.** { *; <init>(...); }
|
||||||
|
|
||||||
|
# .NET runtime
|
||||||
|
-keep class net.dot.android.crypto.** { *; <init>(...); }
|
||||||
|
|
||||||
|
# Android's template misses fluent setters...
|
||||||
|
-keepclassmembers class * extends android.view.View {
|
||||||
|
*** set*(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
# also misses those inflated custom layout stuff from xml...
|
||||||
|
-keepclassmembers class * extends android.view.View {
|
||||||
|
<init>(android.content.Context,android.util.AttributeSet);
|
||||||
|
<init>(android.content.Context,android.util.AttributeSet,int);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user