* fix(android): support source-based APK builds Co-authored-by: Anton Lazarev <22821309+antonok-edm@users.noreply.github.com> * fix(android): address fdroid review feedback Co-authored-by: Anton Lazarev <22821309+antonok-edm@users.noreply.github.com> * fix(android): complete the F-Droid build profile * fix(app): isolate the F-Droid runtime flag --------- Co-authored-by: Anton Lazarev <22821309+antonok-edm@users.noreply.github.com>
4.9 KiB
Android
App variants
Controlled by APP_VARIANT in packages/app/app.config.js (vanilla Expo, no custom Gradle plugin):
| Variant | App name | Package ID |
|---|---|---|
production |
Paseo | sh.paseo |
development |
Paseo Debug | sh.paseo.debug |
EAS profiles: development, production, and production-apk in packages/app/eas.json.
development uses Android debug.
Version codes
packages/app/app.config.js derives Android versionCode from the package version with:
major * 1_000_000 + minor * 1_000 + patch
Prerelease metadata is ignored, so 0.1.102-beta.1 and 0.1.102 both produce 1102. The same value is used as the iOS buildNumber because packages/app/eas.json uses EAS's local app version source. Do not re-enable EAS remote version counters or Android autoIncrement; F-Droid and other source-based builders need the native build number to be visible in the repo.
The formula reserves three digits each for minor and patch. If either reaches 1000, change the formula before cutting that release.
Local build + install
From repo root:
npm run android:development # Debug build
npm run android:production # Release build
npm run android:clear # Remove generated Android project
Or from packages/app:
# Debug
npx cross-env APP_VARIANT=development expo prebuild --platform android --non-interactive
npx cross-env APP_VARIANT=development expo run:android --variant=debug
# Release
npx cross-env APP_VARIANT=production expo prebuild --platform android --non-interactive
npx cross-env APP_VARIANT=production expo run:android --variant=release
# Clear generated Android project
rm -rf android
F-Droid / source-only Android builds
F-Droid builds should set PASEO_FDROID_BUILD=1 when running Expo prebuild:
cd packages/app
PASEO_FDROID_BUILD=1 APP_VARIANT=production npx expo prebuild --platform android --clean --non-interactive
cd android
PASEO_FDROID_BUILD=1 ./gradlew assembleRelease --no-daemon --max-workers=1 -Dorg.gradle.parallel=false
The flag must be present for both prebuild and Gradle because Gradle starts Metro for the release bundle. Keep the source build serial and daemon-free as shown above: compiling every Expo module can exhaust memory when Gradle workers run in parallel. The profile enables source-built Expo modules, excludes the proprietary camera, Firebase notification, and Expo development-client native modules, disables EAS updates and Gradle dependency metadata, and substitutes JavaScript stubs for camera and notifications. The resulting app supports direct and pasted-link pairing but not QR scanning or push notifications.
Keep the excluded npm packages installed. Normal builds use them, while the F-Droid profile removes only their Android native modules and config plugins. Paseo always applies expo-gradle-jvmargs with -Xmx4096m and -XX:MaxMetaspaceSize=1024m so local Expo prebuilds have enough Gradle heap whether they use precompiled AARs or source-built Expo modules.
React version lockstep
Keep react and react-dom pinned to the React version embedded by the current react-native release. React Native 0.81.x embeds react-native-renderer 19.1.0, so packages/app must use React 19.1.0. Bumping React to a newer patch can build successfully but crash at JS startup on Android with Incompatible React versions, leaving the app on the native splash screen.
Screenshots
adb exec-out screencap -p > screenshot.png
Cloud build + submit (EAS)
Stable tag pushes like v0.1.0 trigger:
- The EAS GitHub app on Expo servers (iOS + Android production builds + store submit). There is no workflow file in this repo for it.
.github/workflows/android-apk-release.ymlon GitHub Actions (APK asset on GitHub Release).
iOS auto-submits to App Store review via a Fastlane lane after EAS uploads to TestFlight. Android auto-submits to the Play Store via EAS-managed credentials.
Beta tags like v0.1.1-beta.1 only trigger the GitHub APK workflow. They publish a GitHub prerelease APK for testing and do not submit to the stores.
android-v* tags also trigger only the GitHub APK workflow — useful when you want to ship an APK without going through stores. The GitHub APK workflow supports workflow_dispatch with an existing tag input so you can rebuild without cutting a new tag.
Useful commands
cd packages/app
# Recent builds
npx eas build:list --limit 10 --non-interactive --json | jq '.[] | {platform, status, appVersion, gitCommitHash}'
# Inspect a build (the printed `Logs` URL opens the build's Expo dashboard page,
# which has a Submissions section showing the auto-submit to the Play Store).
npx eas build:view <build-id>
The Play Console (Internal testing → Production tracks) is the final confirmation that the binary reached the store.
See docs/release.md for the full mobile-build babysitting flow.