Reproducible Builds
I've checked your app if its build is reproducible (see: Reproducible bulds, special client support and more in our repo), but while I was able to successfully generate the APK using ./gradlew assembleRelease, there was a load of differences between the two APKs. Start of the APK diff:
-------------------------------
--- /dev/fd/63 2024-07-10 12:47:51.688719016 +0200
+++ /dev/fd/62 2024-07-10 12:47:51.688719016 +0200
@@ -327,7 +327,7 @@
res/0c.9.png
32-bit CRC value (hex): 95bbccff
res/0c.png
- 32-bit CRC value (hex): f5d1119a
+ 32-bit CRC value (hex): 4dbb75d0
res/0n.png
32-bit CRC value (hex): c81c99e6
res/0x.9.png
@@ -393,7 +393,7 @@
res/2x.xml
32-bit CRC value (hex): 4d5f6c8c
res/3-.png
- 32-bit CRC value (hex): a81955ac
+ 32-bit CRC value (hex): 44766c30
res/33.9.png
32-bit CRC value (hex): c5fedfaf
res/35.png
@@ -415,7 +415,7 @@
res/3u.9.png
32-bit CRC value (hex): cff461f2
res/3z.png
- 32-bit CRC value (hex): bd731efa
+ 32-bit CRC value (hex): bab49c82
res/3z1.png
32-bit CRC value (hex): 55f5805d
res/42.9.png
@@ -447,7 +447,7 @@
…
Seems like all the differences were caused by assets (here: PNG), while not all of the PNGs had differences. Which might indicate your build process uses some "crunching" mechanism; those are non-deterministic and hence lead to different results on each run.
We'd appreciate if you could help making your build reproducible. We've prepared some hints on reproducible builds for that. If my guess here is right, you should especially look at the section on "Compressing images" – and the following addition to your build.gradle could cure this:
android {
aaptOptions {
cruncherEnabled = false
}
}
Though I see you already have isCrunchPngs = false set; I'm no Android dev so I cannot tell how the two are related (or if the all section is also applied to the 2 sections above).
Looking forward to your reply!
@oxyroid you're still around? Any word on the above?
I have less time to pay my attention in the repos recently. 🥲
Eh, that happens. And I didn't exactly expect everyone to jump when I open an issue. I was just hoping for some reaction – so thanks for giving it! Now I know you're aware of the problem, but currently have no time to dig in (totally fair). Can you give me any ETA? Is it fine to give you a heads-up here from time to time (maybe once a month or so)?
sry I can't.
I'm stuck in a busy job in a busy department at a busy company.
OK, no worries. Hope its OK for you if I send a friendly heads-up from time to time (not more often than once a month)?
I assume the busy-bees are still keeping you busy?
Ah, a new release! But oh, it got more complicated:
-rw-r--r-- 0.0 unx 56 b- 52 defN 1981-01-01 01:01:02 05cd8676 META-INF/com/android/build/gradle/app-metadata.properties
- -rw-r--r-- 0.0 unx 9423 b- 9423 stor 1981-01-01 01:01:02 d6d4af58 assets/dexopt/baseline.prof
+ -rw-r--r-- 0.0 unx 9423 b- 9423 stor 1981-01-01 01:01:02 683d7ae5 assets/dexopt/baseline.prof
-rw-r--r-- 0.0 unx 1036 b- 1036 stor 1981-01-01 01:01:02 a8d037c8 assets/dexopt/baseline.profm
- -rw-r--r-- 0.0 unx 9783488 b- 4431016 defN 1981-01-01 01:01:02 486ab654 classes.dex
+ -rw-r--r-- 0.0 unx 9783488 b- 4431017 defN 1981-01-01 01:01:02 691b20f3 classes.dex
-rw-r--r-- 0.0 unx 4702512 b- 1885053 defN 1981-01-01 01:01:02 59eda247 classes2.dex
-rw-r--r-- 0.0 unx 10096 b- 10096 stor 1981-01-01 01:01:02 9734baa0 lib/arm64-v8a/libandroidx.graphics.path.so
-rw-r--r-- 0.0 unx 4025264 b- 4025264 stor 1981-01-01 01:01:02 65a4761f lib/arm64-v8a/libavcodec.so
@@ -319,7 +319,6 @@
-rw---- 0.0 fat 658 b- 658 stor 1981-01-01 01:01:02 50ee6e75 res/5v1.png
-rw---- 0.0 fat 228 b- 228 stor 1981-01-01 01:01:02 8210f539 res/5w.png
-rw---- 0.0 fat 553 b- 553 stor 1981-01-01 01:01:02 73ee1c5d res/5y.png
- -rw---- 0.0 fat 158240 b- 70753 defN 1981-01-01 01:01:02 96e21ded res/5z.ttf
-rw---- 0.0 fat 1128 b- 395 defN 1981-01-01 01:01:02 0553f94a res/5z.xml
-rw---- 0.0 fat 1633 b- 1633 stor 1981-01-01 01:01:02 7ed7d2b3 res/6-.png
-rw---- 0.0 fat 796 b- 358 defN 1981-01-01 01:01:02 bc60ca5c res/61.xml
@@ -1278,7 +1277,7 @@
-rw---- 0.0 fat 648 b- 648 stor 1981-01-01 01:01:02 e3a292db res/W51.png
-rw---- 0.0 fat 700 b- 276 defN 1981-01-01 01:01:02 cbd12084 res/W8.xml
-rw---- 0.0 fat 792 b- 792 stor 1981-01-01 01:01:02 cd6c6bda res/W9.png
- -rw---- 0.0 fat 1736 b- 368 defN 1981-01-01 01:01:02 01846845 res/W9.xml
+ -rw---- 0.0 fat 1736 b- 368 defN 1981-01-01 01:01:02 6840d983 res/W9.xml
-rw---- 0.0 fat 396 b- 396 stor 1981-01-01 01:01:02 f3a2968a res/WA.png
-rw---- 0.0 fat 388 b- 388 stor 1981-01-01 01:01:02 c753e16d res/WA1.png
-rw---- 0.0 fat 67 b- 67 stor 1981-01-01 01:01:02 88b2a3b0 res/WB.png
@@ -2686,5 +2685,5 @@
-rw---- 0.0 fat 249 b- 249 stor 1981-01-01 01:01:02 72a34e93 res/zv.png
-rw---- 0.0 fat 435 b- 435 stor 1981-01-01 01:01:02 cc705e7f res/zz.png
-rw---- 0.0 fat 67 b- 67 stor 1981-01-01 01:01:02 88b2a3b0 res/zz1.png
- -rw---- 0.0 fat 2086148 b- 2086148 stor 1981-01-01 01:01:02 8b014e1f resources.arsc
+ -rw---- 0.0 fat 2086088 b- 2086088 stor 1981-01-01 01:01:02 d383df68 resources.arsc
As there's no vcsInfo included with the build, I cannot tell for sure – but either we've built from different commits (I've build from the one the tag points to), or we used different build instructions. I've basically oriented at your workflow and the target APK, so this is the recipe I've used:
build:
- sed -r '/signingConfigs.getByName/d' -i androidApp/build.gradle.kts
- sed -r 's/isUniversalApk = true/isUniversalApk = false/ ; s/include\("x86", "x86_64", "arm64-v8a", "armeabi-v7a"\)/include("arm64-v8a")/' -i androidApp/build.gradle.kts
- chmod +x gradlew
- ./gradlew assembleStableChannelRichCodecRelease
- mv androidApp/build/outputs/apk/stableChannelRichCodec/release/*_arm64-v8a.apk /outputs/unsigned.apk
Line 1 disables signing, line 2 makes sure only the needed APK is produced (to not unnecessarily waste resources).
The diff of classes.dex is rather small:
|: invoke-virtual {v10, v11}, Landroid/widget/ImageView;.setImageDrawable:(Landroid/graphics/drawable/Drawable;)V
|: invoke-virtual {v10, v5}, Landroid/view/View;.setOnClickListener:(Landroid/view/View$OnClickListener;)V
-|: const v11, #float 1.82105e+38 // #7f090010
+|: const v11, #float 1.82105e+38 // #7f09000f
|: invoke-static {v1, v11}, Lx3/o;.a:(Landroid/content/Context;I)Landroid/graphics/Typeface;
But I've no clue where that TTF in your APK came from if it's not in mine… In case it matters: I built with OpenJDK-17 on Debian bookworm.
Any hints?
Maybe I should consider to generate these config files in CI/CD. I generate them on my local computer is a bit unreliable. :(
Glad to see you already have an idea :hugs: We can give it another try anytime, all I'd need is an APK built from a clean tree, so I can build from the same commit to compare.
Not sure what your idea was… I've just tried v1.15.0, and the diff got bigger again:
-rw-r--r-- 0.0 unx 120 b- 117 defN 1981-01-01 01:01:02 59466db9 META-INF/version-control-info.textproto
- -rw-r--r-- 0.0 unx 13715 b- 13715 stor 1981-01-01 01:01:02 ad648647 assets/dexopt/baseline.prof
- -rw-r--r-- 0.0 unx 662 b- 662 stor 1981-01-01 01:01:02 843ae5be assets/dexopt/baseline.profm
- -rw-r--r-- 0.0 unx 2751296 b- 1347909 defN 1981-01-01 01:01:02 4b955835 classes.dex
- -rw-r--r-- 0.0 unx 8648148 b- 3804334 defN 1981-01-01 01:01:02 4572db08 classes2.dex
- -rw-r--r-- 0.0 unx 3187320 b- 1233162 defN 1981-01-01 01:01:02 1547c4cf classes3.dex
+ -rw-r--r-- 0.0 unx 9743 b- 9743 stor 1981-01-01 01:01:02 315e6139 assets/dexopt/baseline.prof
+ -rw-r--r-- 0.0 unx 1467 b- 1467 stor 1981-01-01 01:01:02 cc36edc5 assets/dexopt/baseline.profm
+ -rw-r--r-- 0.0 unx 9569740 b- 4335282 defN 1981-01-01 01:01:02 6b56a9f9 classes.dex
+ -rw-r--r-- 0.0 unx 4720048 b- 1882105 defN 1981-01-01 01:01:02 b27537ed classes2.dex
-rw-r--r-- 0.0 unx 10096 b- 10096 stor 1981-01-01 01:01:02 9734baa0 lib/arm64-v8a/libandroidx.graphics.path.so
-rw-r--r-- 0.0 unx 4025264 b- 4025264 stor 1981-01-01 01:01:02 65a4761f lib/arm64-v8a/libavcodec.so
-rw-r--r-- 0.0 unx 593224 b- 593224 stor 1981-01-01 01:01:02 5f5584f5 lib/arm64-v8a/libavutil.so
@@ -50,15 +49,15 @@
-rw---- 2.0 fat 1140 b- 577 defN 1981-01-01 01:01:02 818edc9a META-INF/ktor-utils.kotlin_module
-rw---- 2.0 fat 88 b- 67 defN 1981-01-01 01:01:02 fe471c6c META-INF/ktor-websocket-serialization.kotlin_module
-rw---- 2.0 fat 355 b- 195 defN 1981-01-01 01:01:02 49a47298 META-INF/ktor-websockets.kotlin_module
- -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 c2313d69 META-INF/services/S6.a
+ -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 ff5114d9 META-INF/services/R6.a
-rw---- 2.0 fat 77 b- 61 defN 1981-01-01 01:01:02 855d9f6e META-INF/services/io.ktor.serialization.kotlinx.KotlinxSerializationExtensionProvider
-rw---- 2.0 fat 40 b- 37 defN 1981-01-01 01:01:02 b667f565 META-INF/services/io.ktor.server.config.ConfigLoader
-rw---- 2.0 fat 91 b- 74 defN 1981-01-01 01:01:02 75f1aa42 META-INF/services/kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader
-rw---- 2.0 fat 236 b- 99 defN 1981-01-01 01:01:02 218b615c META-INF/services/kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition
-rw---- 2.0 fat 57 b- 55 defN 1981-01-01 01:01:02 43ef89c5 META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
- -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 b1d0ce7d META-INF/services/t6.a
- -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 00e2b9ed META-INF/services/u8.A
- -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 2bcfea2e META-INF/services/v8.a
+ -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 03f0126d META-INF/services/s6.a
+ -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 7a22ea8d META-INF/services/s8.z
+ -rw---- 2.0 fat 5 b- 7 defN 1981-01-01 01:01:02 510fb94e META-INF/services/t8.a
-rw---- 2.0 fat 88 b- 70 defN 1981-01-01 01:01:02 2a940232 META-INF/ui_release.kotlin_module
-rw---- 2.0 fat 52 b- 41 defN 1981-01-01 01:01:02 caf6e848 custom.config.conf
-rw---- 2.0 fat 42 b- 35 defN 1981-01-01 01:01:02 45c23b63 custom.config.yaml
@@ -80,7 +79,7 @@
-rw---- 2.0 fat 127010 b- 38582 defN 1981-01-01 01:01:02 af9d74ef org/fusesource/jansi/internal/native/Windows/x86_64/jansi.dll
-rw---- 2.0 fat 14 b- 16 defN 1981-01-01 01:01:02 98cc3806 org/fusesource/jansi/jansi.properties
-rw---- 2.0 fat 935 b- 221 defN 1981-01-01 01:01:02 e6b54850 org/fusesource/jansi/jansi.txt
- -rw---- 0.0 fat 20316 b- 4430 defN 1981-01-01 01:01:02 a8c37ebe AndroidManifest.xml
+ -rw---- 0.0 fat 20344 b- 4443 defN 1981-01-01 01:01:02 8793d117 AndroidManifest.xml
-rw---- 0.0 fat 744 b- 345 defN 1981-01-01 01:01:02 0f30c0af res/-1.xml
I've built the arm64 variant only, disabling the others (I can only compare 1 file against 1 file, so why build them all?). As a result, now even the versionName differs:
ATTR: http://schemas.android.com/apk/res/android:versionCode=144
- ATTR: http://schemas.android.com/apk/res/android:versionName='1.15.0'
+ ATTR: http://schemas.android.com/apk/res/android:versionName='1.15.0_arm64-v8a.apk'
ATTR: http://schemas.android.com/apk/res/android:compileSdkVersion=35
The DEX files I don't even need to diff: a look at their file sizes tells enough.
Do you see any chance that we get that aligned? Any chance I can build an arm64 APK that matches yours – without building all the others along, wasting resources on them?
@oxyroid any word?
Later I will improve the building automation and keep the builds reproducible
Any ETA, so I don't ping you unnecessarily every now and then?