interstellar
interstellar copied to clipboard
Reproducable builds for Android
Description
It looks like with the latest release, v0.3.9, you've decreased versionCode for the APK – which makes Android think this is an older version. Thus the updater at IzzyOnDroid pulls the APK – but the indexer, moving the oldest one out, moves out exactly this APK:
Moving one.jwr.interstellar_19.apk from repo to archive
The 19 is the versionCode here. Previous one we have here was 2017. Almost looks like before, the app was built with versionCode: 17 and --split-per-abi – but the new one with 19 but no --split-per-abi but just --target-platform android-arm64 instead (we're picking the interstellar-android-arm64-v8a.apk, and I guess the ABI code for arm64 is 2, so with --split-per-abi Flutter would use "19 + ABI x 1000 = 2019", but without just "19").
Could you please check? With a lower versionCode, people having a previous version installed will be unable to update, as Android would consider it a downgrade, which is not allowed. So we need to get this fixed 😉
Thanks in advance!
Wait what!?! This has got to be a Flutter issue, cause I haven't messed with anything. I'm definitely still using --split-per-abi in the build action. I'll look into it for sure.
Looks like there's already an issue for it here: https://github.com/flutter/flutter/issues/169790
I've rebuilt the APK files locally with corrected version codes and have uploaded them to the 0.9.3 release. We should be good to go now. Let me know if that fixes it.
Also, thanks for creating the issue here, I had noticed the update from Interstellar wasn't picked up by IzzyOnDroid and was literally about to ping you :)
Thanks to both of you for working out this issue in no time!
I had noticed the update from Interstellar wasn't picked up by IzzyOnDroid and was literally about to ping you :)
@Kelvino9 was faster 😜
I've rebuilt the APK files locally with corrected version codes and have uploaded them to the 0.9.3 release.
Confirming: updater renamed the APK to 2019, so we're back in line. Tried to trigger the RB as well – but ugh, none set up 🤔 Checking notes: ah, I couldn't figure what to set up for that build "then" (about a year ago I guess). Checking again now, it seems I can get it up: you have most if not all details in your Github action, so let me try…
Flutter and JDK versions I get from your workflow. But I'm not sure about what dependencies are needed. I see some mentioned for the Linux build, and some might be required by the Android build as well?
Would you be interested in establishing reproducible builds, @jwr1 (for some background, see e.g. Reproducible Builds, special client support and more at IzzyOnDroid)? If so, shall we make a separate issue for that? Basically, the build fails for me with
lib/src/widgets/markdown/markdown_config_share.dart:143:47: Error: The type 'dynamic' is not exhaustively matched by the switch cases since it doesn't match 'Object()'.
Try adding a wildcard pattern or cases that match 'Object()'.
onPressed: switch (config.type) {
^
lib/src/widgets/markdown/markdown_config_share.dart:172:48: Error: The type 'dynamic' is not exhaustively matched by the switch cases since it doesn't match 'Object()'.
Try adding a wildcard pattern or cases that match 'Object()'.
label: Text(switch (config.type) {
^
Target kernel_snapshot_program failed: Exception
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:compileFlutterBuildRelease'.
> Process 'command '/home/runner/work/interstellar/interstellar/flutter/bin/flutter'' finished with non-zero exit value 1
Maybe I was missing something. My build recipe:
build:
- sed -r 's/signingConfig = keystorePropertiesFile.*/signingConfig = null/' -i android/app/build.gradle
- FLUTTER_VERSION="$(sed -rn 's/\s*flutter-version:\s*([0-9.]+)\s*$/\1/p' .github/workflows/build_release.yml)"
- git clone -b $FLUTTER_VERSION https://github.com/flutter/flutter
- export PUB_CACHE=$(pwd)/.pub-cache
- flutter/bin/flutter config --no-analytics
- flutter/bin/flutter pub get
- flutter/bin/flutter build apk --release --split-per-abi --target-platform android-arm64
Edith: I see I missed the flutter pub run build_runner build, will try that again later. Maybe there are some other hints of yours I should integrate then as well 😉
Confirming: updater renamed the APK to 2019, so we're back in line.
Thanks, I'll close the issue then!
Would you be interested in establishing reproducible builds, @jwr1 (for some background, see e.g. Reproducible Builds, special client support and more at IzzyOnDroid)? If so, shall we make a separate issue for that?
Honestly, I don't really care one way or the other, so feel free to create an issue for RBs if you'd like; I wouldn't mind helping you get it set up.
Flutter and JDK versions I get from your workflow. But I'm not sure about what dependencies are needed. I see some mentioned for the Linux build, and some might be required by the Android build as well?
I don't think there are any additional dependencies needed, not for building for Android at least.
Edith: I see I missed the
flutter pub run build_runner build, will try that again later. Maybe there are some other hints of yours I should integrate then as well 😉
You're right, adding flutter pub run build_runner build will fix the issues you mentioned. The main thing I'm not sure about is how you'll build the app with the correct version name and code, because that's passed in directly through the GH action inputs and not in the source code.
The main thing I'm not sure about is how you'll build the app with the correct version name and code, because that's passed in directly through the GH action inputs and not in the source code.
You pass them manually, or is there any automatism behind it? I mean, if GH actions can get that passed automatically, we should be able to do the same here. Well, let's see how far I get. If it's something we can derive e.g. from the tag name (e.g. versionName = "${TAG_NAME:1}" is easy, just not sure yet where the versionCode would come from; you call that build_number; maybe that could be stored into some text file?), we should be good. Would of course be better were it in the source, yeah…
It's manual. Each time I trigger a release, I need to manually set the version name and code, which are passed in through GH action inputs. I initially set it up that way, because otherwise I would have to create a whole commit every time I want to create a release, just to bump the version number, which I find bothersome.
Though this way, when you look at an older copy of the code, you can never tell which version it belonged to. Plus it makes things like reproducible builds harder. We who maintain such builders would need to manually adjust the recipe each time you release a new version. With more than 600 apps in mine, some days it already takes me 1..2 hours to get failed ones fixed, I couldn't manage if I'd have to manually update all of the recipes…
That said, I was meanwhile able to successfully build using this recipe:
build:
- sed -r 's/signingConfig = keystorePropertiesFile.*/signingConfig = null/' -i android/app/build.gradle
- FLUTTER_VERSION="$(sed -rn 's/\s*flutter-version:\s*([0-9.]+)\s*$/\1/p' .github/workflows/build_release.yml)"
- git clone -b $FLUTTER_VERSION https://github.com/flutter/flutter
- export PUB_CACHE=$(pwd)/.pub-cache
- flutter/bin/flutter config --no-analytics
- flutter/bin/flutter pub get
- sed -r "s/version:\ 0.0.0/version:\ ${APP_TAG:1}\+2019/" -i pubspec.yaml
- flutter/bin/flutter pub run build_runner build
- flutter/bin/flutter build apk --release --split-per-abi --target-platform android-arm64
But not RB. For one, I wonder if that APK was really build using your GH workflow, and not on your local machine from /home/jwr1/Documents/interstellar. The native libraries do not match, which could be due to different build paths; assuming you use the GH action, I've set paths accordingly – but that won't match if you build locally.
So before I sink another hour into test builds: was this APK (arm64) built via the GH action, or locally? Any clues to the other differences?
Though this way, when you look at an older copy of the code, you can never tell which version it belonged to. Plus it makes things like reproducible builds harder. We who maintain such builders would need to manually adjust the recipe each time you release a new version. With more than 600 apps in mine, some days it already takes me 1..2 hours to get failed ones fixed, I couldn't manage if I'd have to manually update all of the recipes…
Alright, I can switch to include the version in the source; I see most other Flutter apps are doing that as well.
But not RB. For one, I wonder if that APK was really build using your GH workflow, and not on your local machine from
/home/jwr1/Documents/interstellar. The native libraries do not match, which could be due to different build paths; assuming you use the GH action, I've set paths accordingly – but that won't match if you build locally.So before I sink another hour into test builds: was this APK (arm64) built via the GH action, or locally? Any clues to the other differences?
The latest APK that I just uploaded ~7 hours ago was built on my local device (due to the issue we're commenting on), but all other releases use GH actions.
Alright, I can switch to include the version in the source; I see most other Flutter apps are doing that as well.
That'd be great – and yes, I can confirm they do.
The latest APK that I just uploaded ~7 hours ago was built on my local device (due to the issue we're commenting on), but all other releases use GH actions.
Ah, that's what I guessed – thanks for confirming! Will give that another try then, but not now (need to get some sleep first). You've built directly from the tagged commit, without any local changes?
I built off of 25dfd18e0d4224b059912040a422ea0bd0f737e0, unfortunately, not the tagged commit from the release (4a838d980e672c834fb4306529ba15566369c627). I also patched Flutter locally with this PR: https://github.com/flutter/flutter/pull/169816. I don't believe I had any other local changes.
I've just updated pubspec.yaml to include both the app version and Flutter version, so you can take both of those from that file. I've also updated the GH workflow to reflect the changes. 213e51730d046f6e94b74d8ac6dac365f52dd68e
I built off of …
Thanks for those details! Building from that commit got the diff smaller. Still a load of diffs for directories (where you've built from, where your pub-cache was placed), so I've tried again with the directories adjusted to your local setup (just to see how far we get). Result: we get VERY close, only difference now is the BuildID in the native libs. That could be dealt with a minor addition to your CMakeLists.txt, adding the line add_link_options("-Wl,--build-id=none") to disable it (details can be found here in our wiki).
I've just updated pubspec.yaml to include both the app version and Flutter version
That's wonderful, thanks! Guess for the final results we best wait for the next release then, to have the build recipe properly adjusted here. I can of course test in advance if you provide me an APK and its corresponding commit hash (no idea why vcsInfo fails here, saying "generate_error_reason: NO_SUPPORTED_VCS_FOUND" for both, your build and ours – I've just peeked into the container, the .git directory is where it should be; this makes it impossible to tell from the APK itself). With the BuildIDs disabled, it should be RB then 🤩
I've just pushed bd4cc0c39e84e7e455c6b3327ec0a452b72960a4 with the change to remove those build-time IDs. Here's my local APK built off of that commit app-arm64-v8a-release.tar.gz.
(note to self: always read each single word carefully. local build = change back all directories from GH to jwr1: home, build dir, cache dir…)
(note 2: remember we haven't patched flutter, so also adjust versionCode in pubspec.yaml)
OK, that done: still the build-ids remaining, I see you've put the --build-id=none into the build.gradle; according to my notes, that's for cmake < 3.13, not sure if recent version recognize it there at all (according to the results, it rather looks like not). I've checked with all the other Flutter apps in our builder, none has that file inside an "android" tree (if at all, just in windows/linux). But then, none needed to suppress the build-id explicitly. No idea if that's something new with 3.32.x as well…
I added it to the grade file because I wasn't seeing any CMakeLists.txt file in the android directory.
I didn't see it in that place with any of the Flutter apps we cover, so I'm a bit clueless there. I don't know if the Android build might take it from the Linux tree then – not being a Flutter dev, my insights there are limited…
A search didn't turn up much for me. Docs say it's "set for ahead-of-time compiled programs" only, since 3.1, but doesn't tell how to disable it. There's this issue on Dart (but that's more for things caused by different paths, which we already matched to our best knowledge – but ends with the question we're at here right now; unfortunately unanswered). That issue has links to similar cases we had in the past, though; do we both use the same Flutter version? Also, which cmake version are you using?
I don't know if the Android build might take it from the Linux tree
Each platform only uses its own platform directory, so the Android build wouldn't be using anything from the linux directory.
Here's my version outputs for CMake (installed from Arch repos) and Flutter:
cmake version 4.0.2-dirty
CMake suite maintained and supported by Kitware (kitware.com/cmake).
Flutter 3.32.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision be698c48a6 (3 weeks ago) • 2025-05-19 12:59:14 -0700
Engine • revision 1881800949 (3 weeks ago) • 2025-05-19 10:54:07 -0700
Tools • Dart 3.8.0 • DevTools 2.45.1
Each platform only uses its own platform directory, so the Android build wouldn't be using anything from the linux directory.
Ah, thanks. I assumed as much, but never knew for sure.
cmake version 4.0.2-dirty
Ugh. Then it's probably that. W cannot match that version, sorry. These are the ones sdkmanager --list gives me as supported:
cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404
cmake;3.18.1 | 3.18.1 | CMake 3.18.1
cmake;3.22.1 | 3.22.1 | CMake 3.22.1
cmake;3.30.3 | 3.30.3 | CMake 3.30.3
cmake;3.30.4 | 3.30.4 | CMake 3.30.4
cmake;3.30.5 | 3.30.5 | CMake 3.30.5
cmake;3.31.0 | 3.31.0 | CMake 3.31.0
cmake;3.31.1 | 3.31.1 | CMake 3.31.1
cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459
Flutter 3.32.0
OK, that matches. So it's most likely the cmake version…
Maybe we should just wait till the next release and hope I don't need to patch Flutter by then.
That PR has been merged 2 weeks ago indeed, and there were 2 new versions tagged since. Which would still leave cmake, though…
If that's the case, then for the next update, we can just use GH actions to build the app (since I wouldn't need to patch Flutter anymore) and I'm assuming the cmake version would be more standard.
@jwr1 I just tried to build 0.10.1. Still the same issue with the embedded build ID, unfortunately. That's the only thing keeping the app from being RB.
I thought I already removed the build ID. What did I do here then? https://github.com/interstellar-app/interstellar/commit/bd4cc0c39e84e7e455c6b3327ec0a452b72960a4
We tried removing it, but it did not work out. As our wiki states, for reasons unknown to us, sometimes one method works, sometimes you need the other one. It's yet unclear (at least to me) why, or how to detect which would be the correct approach – other than trying and checking the results.