Reproduzierbare Builds

F-Droid unterstützt reproduzierbare Builds von Apps, so dass jeder den Build-Prozess erneut ausführen und das gleiche APK wie das Original-Release reproduzieren kann. Dies bedeutet, dass F-Droid überprüfen kann, ob eine Anwendung 100% freie Software ist, während die APK-Signaturen des ursprünglichen Entwicklers verwendet werden. F-Droid verifiziert reproduzierbare Builds anhand von APK-Signaturkopie.

Dieses Konzept wird gelegentlich als „deterministische Builds“ bezeichnet. Das ist ein viel strengerer Standard: es bedeutet, dass der gesamte Prozess jedes Mal in der gleichen Reihenfolge abläuft. Das Wichtigste ist, dass jeder den Prozess ausführen kann und am Ende genau das gleiche Ergebnis hat.

Wie es ab sofort umgesetzt wird

Die Veröffentlichung signierter Binärdateien (APKs) von anderswo (z. B. vom Upstream-Entwickler) ist nun möglich, wenn die Überprüfung zeigt, dass sie nach Herstellung mittels eines fdroiddata-Rezeptes exakt übereinstimmen. Dieser Vorgang ist als Teil von fdroid publish implementiert. Die Prüfung der Reproduzierbarkeit im Veröffentlichungsschritt folgt dieser Logik:

Flussdiagramm zur Reproduzierbarkeitsprüfung

Veröffentlichung von APKs, die sowohl von (Upstream-)Entwicklern als auch von F-Droid signiert sind

Diese Vorgehensweise ermöglicht eine Veröffentlichung sowohl von APKs, die vom (Upstream-)Entwickler signiert sind, als auch solchen, die von F-Droid signiert sind. Dies versetzt uns in die Lage, Aktualisierungen an Benutzer auszuliefern, die Apps aus anderen Quellen als F-Droid (z. B. aus dem Play Store) installiert haben, und gleichzeitig Aktualisierungen für Apps zu verschicken, die von F-Droid erstellt und signiert wurden.

Dazu müssen (Upstream-)Entwicklersignaturen extrahiert und in fdroiddata eingefügt werden. Diese Signaturen werden dann später aus dem fdroiddata-Rezept in die unsignierte APK kopiert. Wir bieten einen Befehl zum einfachen Extrahieren von Signaturen aus APKs:

$ cd /pfad/zum/fdroiddata
$ fdroid signatures F-Droid.apk

Anstelle von lokalen Dateien können Sie auch HTTPS-URLs an fdroid signatures übergeben.

Die Signaturdateien werden gebrauchsfertig für fdroid publish in das entsprechende Metadatenverzeichnis der App extrahiert. Eine Signatur besteht aus 2-6 Dateien: einer v1-Signatur (Manifest, Signatur-Datei und Signatur-Blockdatei) und/oder einer v2/v3-Signatur (APK-Signier-Block und Offset); war die APK mit z. B. signflinger statt apksigner v1-signiert, gibt es zusätzlich eine differences.json. Das Ergebnis des Extrahierens ähnelt diesen Dateilisten:

$ ls metadata/org.fdroid.fdroid/signatures/1000012/  # v1 signature only
CIARANG.RSA  CIARANG.SF  MANIFEST.MF
$ ls metadata/your.app/signatures/42/                # v1 + v2/v3 signature
APKSigningBlock  APKSigningBlockOffset  MANIFEST.MF  YOURKEY.RSA  YOURKEY.SF

Wenn Sie fdroidserver nicht installieren wollen (oder eine ältere Version haben, die das Extrahieren von v2/v3-Signaturen noch nicht unterstützt), können Sie auch apksigcopier (verfügbar z. B. in Debian, Ubuntu, Arch Linux, NixOS) anstelle von fdroid signatures verwenden:

$ cd /path/to/fdroiddata
$ APPID=your.app VERSIONCODE=42
$ mkdir metadata/$APPID/signatures/$VERSIONCODE
$ apksigcopier extract --v1-only=auto Your.apk metadata/$APPID/signatures/$VERSIONCODE

Veröffentlichung von APKs, die ausschließlich von (Upstream-)Entwicklern signiert sind

Um diesen älteren Ansatz zu verwenden, sollte alles in den Metadaten wie üblich sein plus der Anweisung Binaries:, um festzulegen, woher die Binärdateien (APKs) kommen sollen. In diesem Fall wird F-Droid niemals versuchen, von F-Droid signierte APKs zu veröffentlichen. Wenn fdroid publish verifizieren kann, dass das heruntergeladene APK mit dem nach dem fdroiddata-Rezept hergestellten übereinstimmt, wird das heruntergeladene APK veröffentlicht. Andernfalls überspringt F-Droid die Veröffentlichung dieser Version der App.

Hier ein Beispiel für eine Binaries-Anweisung:

Binaries: https://example.com/path/to/myapp-%v.apk

Siehe auch: Build-Metadaten-Referenz - Binaries

Reproduzierbare Signaturen

F-Droid verifiziert reproduzierbare Builds anhand der APK-Signatur (eine Form von eingebetteter Signatur, was das Kopieren der Signatur von einer signierten APK auf eine unsignierte APK erfordert, um dann zu prüfen, ob letztere verifiziert werden kann. Die alten v1 (JAR)-Signaturen decken nur den Inhalt der APK ab (z. B. ZIP-Metadaten und Reihenfolge sind irrelevant), aber v2/v3-Signaturen decken alle anderen Bytes in der APK ab. Die APKs müssen also vor und nach dem Signieren völlig identisch sein (abgesehen von der Signatur), um korrekt verifiziert werden zu können.

Das Kopieren der Signatur verwendet denselben Algorithmus, den apksigner beim Signieren einer APK verwendet. Es ist daher wichtig, dass (Upstream-)Entwickler beim Signieren von APKs dasselbe tun, idealerweise mit apksigner.

Verifikations-Builds

Viele Leute oder Organisationen werden daran interessiert sein, Builds zu reproduzieren, um sicherzustellen, dass die f-droid.org-Builds mit dem ursprünglichen Quellcode übereinstimmen und nichts verändert wurde. In diesem Fall werden die resultierenden APKs nicht zur Installation veröffentlicht. Der Verifikationsserver automatisiert diesen Vorgang.

Reproduzierbare Builds

Etliche Builds verifizieren bereits ohne zusätzlichen Aufwand, da Java-Code oft von einer Vielzahl von Java-Versionen in den gleichen Bytecode kompiliert wird. Die build-tools des Android-SDKs erzeugen Unterschiede in den resultierenden XML-, PNG-, usw. Dateien, aber das ist normalerweise kein Problem, da die build.gradle die genaue Version von build-tools enthält.

Alles, was mit dem NDK gebaut wird, ist viel empfindlicher. Selbst für Builds, die genau die gleiche Version des NDK verwenden (z. B. r13b), aber auf verschiedenen Plattformen (z. B. macOS gegenüber Ubuntu), werden die resultierenden Binärdateien Unterschiede aufweisen.

Zusätzlich müssen wir nach allem Ausschau halten, was Zeitstempel oder Build-Pfade, Sortierreihenfolge usw. enthält.

Google arbeitet auch an reproduzierbaren Builds von Android-Apps, so dass die Verwendung aktueller Versionen des Android-SDKs hilft. Ein spezieller Fall beginnt mit dem Gradle Android Plugin v2.2.2, Zeitstempel in den ZIP-Metadaten der APK-Datei werden automatisch auf Null gesetzt.

Debugging reproduzierbarer Builds

Empfohlene Werkzeuge

Wir empfehlen die Verwendung von diffoscope, um die Unterschiede zwischen dem von den App-Entwicklern bereitgestellten Referenz-APK und dem APK, das fdroidserver herstellte, herauszufinden.

Sie finden das APK, das fdroidserver herstellte entweder unter z. B. fdroiddata/build/com.example.app/app/build/outputs/apk/prod/release/example-1.0.0-prod-release-unsigned.apk (wenn er lokal läuft) oder in den Pipeline Artifacts (bei Verwendung von GitLab CI). Passen Sie den Pfad entsprechend an (z. B. für von prod abweichenden Varianten).

Priorisierung und Beheben von Unterschieden

Die Anleitung: APKs für Reproduzierbare Builds differenzieren und einrichten im Wiki von F-Droid enthält detaillierte Informationen über die verschiedenen Arten der im Allgemeinen anzutreffenden Abweichungen, welchen Abweichungen normalerweise beim Debugging der Vorzug gegeben werden sollte und wie verbreitete Probleme gelöst werden.

Sie zeigt auch, wie verschiedene spezialisierte Tools verwendet werden können, die möglicherweise bessere Ergebnisse liefern, wenn diffoscope nicht ausreicht.

Reproduzierbare APK-Tools

Die Skripte aus reproducible-apk-tools (als srclib in fdroiddata enthalten) können dabei helfen, Builds reproduzierbar zu gestalten, z. B. durch Korrektur von Zeilenvorschüben (CRLF gegen LF) oder Schaffung einer deterministischen ZIP-Ordnung, wenn die Entfernung der für die Unterschiede verantwortlichen Ursachen keine realistische Option bietet. Abhängig von speziellen Details, müssen diese Skripte von Upstream-Entwicklern vor dem Signieren ihrer APKs durch sie selbst und/oder durch das fdroiddata-Rezept angewandt werden.

Ursprünglich geschaffen, um Non-Determinismus in den Build-Vorgang einzuführen, kann disorderfs auch das Gegenteil ausführen: das Auslesen des Dateisystems deterministisch vornehmen. In einigen Fällen kann dies z. B. resources.arsc reproduzierbar machen. Hier ein Beispiel eines bestehenden Rezepts:

$ mv my.app my.app_underlying
$ disorderfs --sort-dirents=yes --reverse-dirents=no my.app_underlying my.app

Mögliche Ursachen für nicht reproduzierbare Builds

Es gibt verschiedene Möglichkeiten, wie Builds nicht reproduzierbar sein können. Einige sind relativ leicht zu vermeiden, andere sind schwer zu beheben. Im Folgenden haben wir versucht, einige häufige Ursachen aufzulisten.

Siehe auch dieses GitLab-Ticket.

Fehler: Android Studio-Builds haben eine nicht-deterministische ZIP-Reihenfolge

Nicht vorhersehbare Reihenfolge der ZIP-Einträge in APK macht Builds unreproduzierbar (erfordert möglicherweise ein Google-Konto zur Ansicht).

Hinweis: Dies sollte in Android Gradle Plugin (com.android.tools.build:gradle / com.android.application) 7.1.X und später behoben werden.

Bei der Erstellung von APKs mit Android Studio kann die Reihenfolge der ZIP-Einträge in der APK anders sein als bei APKs, die durch den direkten Aufruf von gradle erstellt wurden, was die Reproduzierbarkeit beeinträchtigt; die Reihenfolge kann völlig unbestimmt sein und sich sogar zwischen verschiedenen Builds desselben Quellcodes unterscheiden.

Ein Workaround für ältere Versionen ist der direkte Aufruf von gradle (wie bei F-Droid oder CI-Builds) unter Umgehung von Android Studio:

$ ./gradlew assembleRelease

NB: Je nach Ihrer Signierkonfiguration kann es erforderlich sein, die APK anschließend mit apksigner zu signieren, da die Signierung in diesem Fall nicht von Android Studio durchgeführt wird.

Fehler: baseline.profm nicht deterministisch

Non-stable assets/dexopt/baseline.profm (erfordert möglicherweise ein Google-Konto zur Ansicht).

Siehe auch diesen Bericht über Abhilfen.

Fehler: coreLibraryDesugaring nicht deterministisch

Hinweis: Dies sollte in R8 (com.android.tools:r8) ab Version 3.0.69 behoben sein.

In einigen Fällen sind Builds nicht reproduzierbar aufgrund eines Fehlers in coreLibraryDesugaring (erfordert möglicherweise ein Google-Konto zur Ansicht); dies betraf NewPipe.

Bug: Unterschiede in den Zeilenendungen zwischen Windows- und Linux-Builds

Unterschiede am Zeilenende zwischen Builds unter Windows und Linux machen sie unreproduzierbar (erfordert möglicherweise ein Google-Konto, um angezeigt zu werden).

Eine Abhilfe besteht darin, fix-newlines.py auf der unsignierten APK mit den “falschen” Zeilenenden auszuführen, um sie von LF in CRLF zu ändern (oder umgekehrt mit --from-crlf) und es danach wieder zu zipalignen.

Parallelität: Die Reproduzierbarkeit kann von der Anzahl der CPUs/Kerne abhängen

Dies kann .dex Dateien (obwohl dies selten zu sein scheint) oder nativen Code (z. B. Rust) betreffen.

Verwendung von nur 1 CPU/Kern als Workaround:

export CPUS_MAX=1
export CPUS=$(getconf _NPROCESSORS_ONLN)
for (( c=$CPUS_MAX; c<$CPUS; c++ )) ; do echo 0 > /sys/devices/system/cpu/cpu$c/online; done

Hinweis: Diese Umgehung wirkt sich auf die gesamte Maschine aus, daher wird empfohlen, sie in einer nicht-persistenten virtuellen Maschine oder einem Container zu verwenden.

Für Rust-Code können Sie codegen-units = 1 einstellen.

Siehe auch dieses GitLab-Ticket.

Eingebettete Buildpfade

Eingebettete Build-Pfade sind eine Quelle für Probleme mit der Reproduzierbarkeit, die Apps betreffen, die z. B. mit Flutter, python-for-android oder mit nativem Code (z. B. Rust, C/C++, jede Art von libfoo.so) erstellt wurden. Apps, die vollständig in Java und/oder Kotlin geschrieben wurden, sind in der Regel nicht davon betroffen.

Oft ist die einfachste Lösung, immer dasselbe Arbeitsverzeichnis für die Erstellung zu verwenden, z. B. /builds/fdroid/fdroiddata/build/your.app.id (F-Droid CI), /home/vagrant/build/your.app.id (F-Droid build server), /tmp/build, oder eines zu erstellen, um die vom Upstream verwendeten Ordner zu spiegeln, z. B. für macOS /Users/runner.

Hinweis: Die Verwendung eines Unterverzeichnisses im von allen beschreibbaren /tmp kann (auf Mehrbenutzersystemen) zu Sicherheitsbeeinträchtigungen führen.

Wenn der SDK-Pfad in Flutter eingebettet endet, kann man das SDK in der Rezeptur in den besagten Pfad verschieben und es mit: flutter config --android-sdk <path> konfigurieren, da die Festlegung von ANDROID_SDK_ROOT unter Umständen nicht ausreichend sein kann.

Eingebettete Zeitstempel

Eingebettete Zeitstempel sind die häufigste Ursache für Probleme mit der Reproduzierbarkeit und sollten vermieden werden.

Native Bibliothek strippen

Es scheint, dass das Strippen von nativen Bibliotheken, z. B. libfoo.so, zeitweise Reproduzierbarkeitsprobleme verursachen kann. Es ist wichtig, beim Neuaufbau die genaue NDK-Version zu verwenden, z. B. r21e. Das Deaktivieren von Stripping kann manchmal helfen. Gradle scheint freigegebene Bibliotheken standardmäßig zu strippen, auch wenn die App die freigegebenen Bibliotheken über eine AAR-Bibliothek erhält. Hier erfahren Sie, wie Sie es in Gradle deaktivieren können:

android {
    packagingOptions {
        doNotStrip '**/*.so'
    }
}

NDK build-id

Auf verschiedenen Build-Maschinen werden unterschiedliche NDK-Pfade und unterschiedliche Pfade zum Projekt (und damit zu seinem jni-Verzeichnis) verwendet. Dies führt zu unterschiedlichen Pfaden zu den Quelldateien in Debug-Symbolen, was den Linker veranlasst, eine andere Build-ID zu erzeugen, die nach dem Strippen erhalten bleibt.

Eine mögliche Lösung ist die Übergabe von --build-id=none an den Linker, der die build-id-Erzeugung komplett deaktiviert.

NDK-Hash-Stil

LLVM übergibt verschiedene Standards an Linker auf verschiedenen Plattformen. Nachdem dieser Commit ins NDK integriert wurde, wird in Debian --hash-style=gnu als Standard verwendet. Um den Hash-Typ zu ändern, kann --hash-style=gnu an den Linker übergeben werden.

platform Revisionen

Im Jahr 2014 wurden die Android SDK-Tools geändert auf stick two data elements in AndroidManifest.xml als Teil des Build-Prozesses: platformBuildVersionName und platformBuildVersionCode. platformBuildVersionName enthält die „Revision“ des Pakets platform, gegen das gebaut wurde (z. B. android-23), jedoch können verschiedene “Revisionen” desselben Pakets platform nicht parallel installiert werden. Außerdem unterstützen die SDK-Tools nicht die Angabe der erforderlichen Revision als Teil des Build-Prozesses. Dies führt oft zu einem ansonsten reproduzierbaren Build, wobei der einzige Unterschied das Attribut platformBuildVersionName ist.

Die platform ist Teil des Android SDK, das die Standardbibliothek darstellt, die auf dem Telefon installiert ist. Die Version besteht aus zwei Teilen: „Versionscode“, eine ganze Zahl, die das SDK-Release repräsentiert, und die „Revision“, die Bugfix-Versionen für jede Plattform repräsentiert. Diese Versionen sind in der mitgelieferten Datei build.prop zu finden. Jede Revision hat eine andere Nummer in ro.build.version.incremental. Gradle hat keine Möglichkeit, die Revision in compileSdkVersion oder targetSdkVersion anzugeben. Es kann jeweils nur eine Plattform-23 installiert werden, im Gegensatz zu build-tools, wo jede Version parallel installiert werden kann.

Hier sind zwei Beispiele, bei denen alle Unterschiede vermutlich von verschiedenen Revisionen der Plattform herrühren:

  • https://verification.f-droid.org/de.nico.asura_12.apk.diffoscope.html
  • https://verification.f-droid.org/de.nico.ha_manager_25.apk.diffoscope.html

PNG Crush/Crunch

Ein Standardbestandteil des Android-Buildprozesses ist es, eine Art PNG-Optimierungswerkzeug wie aapt singleCrunch, pngcrush, zopflipng oder optipng auszuführen. Diese liefern keine deterministische Ausgabe, es ist immer noch eine offene Frage, warum. Da PNGs normalerweise in das Quell-Repo committed sind, besteht eine Lösung für dieses Problem darin, das Tool Ihrer Wahl auf den PNG-Dateien auszuführen und diese Änderungen dann in das Quell-Repo zu übertragen (z. B. git). Deaktivieren Sie dann den standardmäßigen PNG-Optimierungsprozess, indem Sie diesen in build.gradle einfügen:

android {
    aaptOptions {
        cruncherEnabled = false
    }
}

Zu beachten ist, dass Werkzeuge wie svgo ähnliche Optimierungen an SVG-Dateien vornehmen können.

PNGs, die aus Vektorgrafiken erzeugt wurden

Android Gradle Plugin generiert PNG-Ressourcen aus Vektor-Drawables für alte Android-Versionen. Leider sind die generierten PNG-Dateien nicht reproduzierbar.

Sie können die Generierung der PNGs deaktivieren, indem Sie dies zu build.gradle hinzufügen:

android {
    defaultConfig {
        vectorDrawables.generatedDensities = []
    }
}

R8-Optimierer

Es kommt vor, dass einige R8-Optimierungen nicht-deterministisch sind und bei verschiedenen Build-Durchläufen unterschiedlichen Bytecode erzeugen.

Beispielsweise versucht R8, die ServiceLoader-Nutzung zu optimieren, indem eine statische Liste aller Dienste im Code erzeugt wird. Die Anordnung dieser Liste kann bei jedem Build-Durchlauf unterschiedlich (oder sogar unvollständig) sein. Die einzige Möglichkeit, dieses Verhalten zu verhindern, ist die Deaktivierung solcher Optimierungen durch Deklaration optimierter Klassen in proguard-rules.pro:

-keep class kotlinx.coroutines.CoroutineExceptionHandler
-keep class kotlinx.coroutines.internal.MainDispatcherFactory

Seien Sie vorsichtig im Umgang mit R8. Testen Sie Ihre Builds immer mehrere Male und deaktivieren Sie Optimierungen, die nicht-deterministische Ausgaben erzeugen.

Ressourcen schrumpfen

Es ist möglich die APK-Dateigröße zu reduzieren, indem nicht verwendete Ressourcen aus dem Paket entfernt werden. Das ist praktisch, wenn ein Projekt von bestimmten aufgeblähten Bibliotheken, wie AppCompat, abhängt, insbesondere wenn R8/ProGuard zum Schrumpfen des Codes verwendet wird.

Allerdings kann es geschehen, dass der Ressourcen-Schrumpfer die APK-Größe auf verschiedenen Plattformen erhöht, insbesondere wenn es nicht viele Ressourcen zu schrumpfen gibt, sodass dann das Original-APK anstatt des geschrumpften verwendet wird (nicht-deterministisches Verhalten des Gradle-Plugin). Vermeiden Sie die Verwendung des Ressourcen-Schrumpfers, solange die APK-Dateigröße nicht signifikant verkleinert wird.

ZIP-Metadaten

APKs verwenden das ZIP-Dateiformat, das ursprünglich für das MSDOS FAT-Dateisystem entwickelt wurde. UNIX-Dateiberechtigungen wurden als Erweiterung hinzugefügt. APKs benötigen nur das einfachste ZIP-Format, ohne irgendwelche Erweiterungen. Diese Erweiterungen werden oft bei der finalen Versionssignierung entfernt. Aber der APK-Build-Prozess kann sie hinzufügen. Zum Beispiel:

--- a2dp.Vol_137.apk
+++ sigcp_a2dp.Vol_137.apk
@@ -1,50 +1,50 @@
--rw----     2.0 fat     8976 bX defN 79-Nov-30 00:00 AndroidManifest.xml
--rw----     2.0 fat  1958312 bX defN 79-Nov-30 00:00 classes.dex
--rw----     1.0 fat    78984 bx stor 79-Nov-30 00:00 resources.arsc
+-rw-rw-rw-  2.3 unx     8976 b- defN 80-000-00 00:00 AndroidManifest.xml
+-rw----     2.4 fat  1958312 b- defN 80-000-00 00:00 classes.dex
+-rw-rw-rw-  2.3 unx    78984 b- stor 80-000-00 00:00 resources.arsc

Nicht zusammenpassende Toolchains

Verschiedene Werkzeug-Programme können unterschiedliche Binärdateien erzeugen. Für gewöhnlich ist das so, wenn mehr als eine JDK-Version/Distribution verwendet werden, um das APK herzustellen. Manchmal kann sogar Gradle verschiedene JDK-Versionen beim Build eines APK mischen. Um solche Probleme zu vermeiden, sollten ungenutzte JDKs entfernt werden.

Das APK diff wird in den classes.dex-Dateien Einträge wie diese aufweisen, z. B. Java 17 vs. Java 11:

-    .annotation system Ldalvik/annotation/Signature;
-        value = {
-            "()V"
-        }
-    .end annotation

Sprachspezifische Anweisungen

Native Bibliotheken können mit verschiedenen Werkzeugen und in vielen Sprachen erzeugt werden. Auch wenn sie mit ähnlichen Schwierigkeiten bei der Reproduzierbarkeit kämpfen, sind die Methoden, diese zu lösen, verschieden. Einige bekannte Lösungen sind im Folgenden aufgelistet:

ndk-build

LOCAL_LDFLAGS += -Wl,<linker args> können in Android.mk-Dateien oder build.gradle/build.gradle.kts ergänzt werden:

android {
    defaultConfig {
        externalNativeBuild {
            ndkBuild {
                arguments "LOCAL_LDFLAGS += -Wl,<linker args>"
            }
        }
    }
}
CMake

For CMake versions since 3.13, add_link_options(LINKER:<linker args>) can be added to CMakeLists.txt globally. For CMake versions before 3.13, target_link_libraries(<target> LINKER:<linker args>) can be used instead for every target. It can also be set in Gradle files:

android {
    defaultConfig {
        externalNativeBuild.cmake {
          cFlags "-DCMAKE_SHARED_LINKER_FLAGS=-Wl,<linker args>"
        }
    }
}

-ffile-prefix-map can be used to remove embedded build path.

Golang

Linker-Argumente können zu CGO_LDFLAGS hinzugefügt werden. Einige weitere hilfreiche Argumente, die an go build übergeben werden können, sind -ldflags="-buildid=", -trimpath (um eingebettete Build-Pfade zu vermeiden) und -buildvcs=false.

Rust

Compiler- und Linker-Argumente können in Cargo build.rustflags und rustc Codegen Options ergänzt werden. Linker-Argumente können mit -C link-args=-Wl,<linker args> hinzugefügt werden; --remap-path-prefix=<old>=<new> kann eingefügt werden, um Build-Pfade zu zerlegen.

Die Rust-Toolchain sollte an dieselbe Version wie die des Upstreams geheftet werden. Dies kann bei der Installation von „rustup“ mit rustup-init.sh -y --default-toolchain <version> erledigt werden.

Library-specific instructions

Some libraries generate non-deterministic code due to timestamps, unsorted iterations etc. Some known fixes are documented below:

Gradle-Plugin AboutLibraries

Sie können verhindern, dass dieses Plugin (com.mikepenz.aboutlibraries.plugin) einen Zeitstempel zu der JSON-Datei hinzufügt, die es erzeugt, indem Sie dies zu build.gradle hinzufügen:

aboutLibraries {
    // Entfernen Sie den Zeitstempel "generated", um reproduzierbare Builds zu ermöglichen
    excludeFields = ["generated"]
}

Fügen Sie für build.gradle.kts stattdessen Folgendes hinzu:

aboutLibraries {
    // Entfernen Sie den "generated" Zeitstempel, um reproduzierbare Builds zu ermöglichen
    excludeFields = arrayOf("generiert")
}
EventBus

It generates non-deterministic code which can be sorted after the classes are generated. The detailed instructions can be found in Eternity’s source code.

Migration zu reproduzierbaren Builds

TODO

  • jar-Sortierreihenfolge für APKs
  • aapt Versionen liefern unterschiedliche Ergebnisse (XML und res/ Unterordnernamen)

Quellen