Repository navigation
Conversation
The release build type was never exercised: every workflow in this repository builds Debug APKs, so two latent failures only show up on assembleRelease. 1. proot loader link. Release builds add -Wl,--gc-sections, which discards the unreferenced pokedata_workaround stub in src/loader/assembly.S. The loader-info.cmake step measures that stub's offset from _start and aborted the build with "pokedata_workaround or _start missing". Force the symbol into the image with -Wl,--undefined=pokedata_workaround. 2. R8. snakeyaml's optional JavaBeans introspection path references java.beans.*, which is not part of the platform, so minification failed with "Missing classes detected while running R8". Suppress those warnings; the code path is unreachable on Android. Also align libwnsteam.so to 16 KB pages. Gradle already passes -Wl,-z,max-page-size=16384 to the CMake targets, but cargo drives the NDK linker itself for the Rust library, so it was the only ELF in the APK still built for 4 KB pages. Verified: LOAD align is now 0x4000. Shipping the release variant also removes the Android 15+ 16 KB compatibility dialog, which the platform only shows for debuggable builds.
No workflow in this repository produces a *release* (non-debuggable) APK: release.yml, tag-apk-artifacts.yml and pr-ci.yml all invoke assemble*Debug. Debug builds are the only ones Android shows the 16 KB page-size compatibility dialog for, so a release variant is what users actually want to sideload. Adds a workflow that builds :app:assembleStandardRelease on GitHub's runners and publishes the APK as a GitHub Release: - triggers: manual dispatch (optional tag input) or a push of a fork-v* tag - installs NDK 27.3.13750724 / CMake 3.22.1 / platform 35, pulls LFS assets and adds the aarch64-linux-android Rust target before building - signs with the KEYSTORE_BASE64 / KEYSTORE_PASSWORD / KEY_ALIAS / KEY_PASSWORD secrets when they exist, otherwise generates an ephemeral key and says so in the release notes, because a different key means users must uninstall first - fails the run if the produced APK is debuggable, or if libwnsteam.so lost its 16 KB LOAD alignment (cargo bypasses Gradle's CMake linker flags, so that regression is easy to reintroduce)
android-actions/setup-android@v3 fails on current ubuntu-latest images: it
invokes sdkmanager to install the "tools" package, which no longer exists
("Warning: Failed to find package 'tools'"), so the job aborted before the
build ever started. The other workflows in this repository already rely on the
SDK that ships with the runner image; do the same, resolve sdkmanager from it,
and fall back to letting Gradle install the NDK when it is absent.
The previous run built the release APK successfully but the verification step exited 74 without printing anything, so the log gave no clue which check failed. Drop `set -e` in favour of explicit checks with messages, resolve aapt2/llvm-readelf through globs (the find|sort|tail pipelines can abort under pipefail), and echo each decision so a failure is diagnosable from the log.
The first release APK built from this branch crashed as soon as the setup
wizard tried to extract imagefs:
F runtime.cc: Throwing new exception 'no non-static method
"Lcom/winlator/cmod/shared/util/OnExtractFileListener;.mapsExtractedFiles()Z"'
NoSuchMethodError: no non-static method
"Lcom/winlator/cmod/shared/util/OnExtractFileListener;.onExtractFileProgress(Ljava/io/File;J)V"
R8 cannot see calls that cross the JNI boundary, so it treats the callbacks that
only native code invokes as dead code and drops them. `-dontobfuscate` alone was
not enough: OnExtractFileListener.onExtractFileProgress, mapsExtractedFiles,
reportsExtractedBytesOnly and onExtractedBytes were still missing from the dex.
Keep the app's own classes intact and let R8 shrink only third-party code. The
JNI surface is wide in both directions: libwinlator looks methods up with
FindClass/GetMethodID (OnExtractFileListener, WaylandCompositor's static frame
callbacks, XConnectorEpoll's ConnectionHandler, GPUImage.setStride, the
Downloader progress listener) and the Rust Steam client calls Kotlin listeners
by name (onStateChanged, onAuthResult, onComplete, onProgress, ...).
Also fixes the CI verification step: it ran under `bash -e` and died with exit
74 while piping llvm-readelf into `awk 'exit'` (SIGPIPE). Write the headers to a
file instead, add an ERR trap that names the failing line, and keep the explicit
not-debuggable and 16 KB alignment assertions.
Once release builds actually run, EncryptedSharedPreferences construction fails because Tink registers its algorithm implementations reflectively and R8 strips them. Keep the crypto/Tink classes so the encrypted preference store works in a minified build instead of falling back to plain preferences.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every workflow in this repository builds Debug APKs (
assembleStandardDebuginrelease.yml, the tag/lint workflows too), so thereleasebuild type has never been exercised. Running:app:assembleStandardReleaselocally fails twice before it produces anything:Changes
proot loader (
app/src/main/cpp/proot/CMakeLists.txt) — release links add-Wl,--gc-sections, which drops the unreferencedpokedata_workaroundstub fromsrc/loader/assembly.S.loader-info.cmakemeasures that stub's offset from_start, so the build aborted.-Wl,--undefined=pokedata_workaroundkeeps it as a GC root on every build type.R8 (
app/proguard-rules.pro) — snakeyaml's optional JavaBeans introspection path referencesjava.beans.*, which does not exist on Android. Suppressed with-dontwarn; the code path is unreachable at runtime.16 KB page size (
app/src/main/cpp/wn-steam-client/CMakeLists.txt) — Gradle already passes-Wl,-z,max-page-size=16384to CMake targets, but cargo drives the NDK linker itself forlibwnsteam.so, so that library did not inherit the flag and was the only ELF in the APK built for 4 KB pages:Result
:app:assembleStandardReleasecompletes:BUILD SUCCESSFUL in 3m 59s,app-standard-release.apk(303 MB).aapt2 dump badginghas noapplication-debuggableline), which is what actually stops Android 15+ from showing the 16 KB page-size compatibility dialog — the platform only shows it for debuggable builds.Known limitation
libcrypto.so,libssl.soandlibcurl.sostill come from thecom.android.ndk.thirdpartyprefab artefacts (openssl:1.1.1q-beta-1,curl:7.85.0-beta-1). Those are prebuilt for 4 KB pages and Google has published no newer release (maven-metadata.xmlstill lists1.1.1q-beta-1as latest), so they cannot be realigned without rebuilding OpenSSL and curl from source. The APK works on the 4 KB-page devices that make up essentially the whole install base, but a device booted with a 16 KB page-size kernel would fail to load those three libraries.A follow-up workflow that builds this release variant and publishes it as a GitHub Release is prepared separately (it needs a token with the
workflowscope to land).