Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/workflows/formulus-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
retention-days: 7

build-android:
name: Build Formulus Android APK
name: Build Formulus Android
runs-on: ubuntu-latest
needs: build-formplayer-assets
permissions:
Expand Down Expand Up @@ -121,6 +121,16 @@ jobs:
working-directory: formulus
run: pnpm run vendor:notifee

- name: Apply FOSS Android patches (match F-Droid init)
if: github.event_name != 'pull_request'
working-directory: formulus
run: pnpm run patch:android-foss

- name: Generate injection script (match F-Droid init)
if: github.event_name != 'pull_request'
working-directory: formulus
run: pnpm run generate

- name: Set up Java
uses: actions/setup-java@v4
with:
Expand Down Expand Up @@ -166,18 +176,32 @@ jobs:
working-directory: formulus/android
run: ./gradlew assembleRelease --no-daemon

- name: Build release AAB for Play Store (main/dev/release)
if: github.event_name != 'pull_request'
working-directory: formulus/android
run: ./gradlew bundleRelease --no-daemon

- name: Upload APK artifact
uses: actions/upload-artifact@v6
with:
name: formulus-android-apk-${{ github.event_name }}-${{ github.run_id }}
path: |
formulus/android/app/build/outputs/apk/**/**/*.apk

- name: Upload AAB artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v6
with:
name: formulus-android-aab-${{ github.event_name }}-${{ github.run_id }}
path: |
formulus/android/app/build/outputs/bundle/release/*.aab

- name: Upload APK to GitHub Release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
files: |
formulus/android/app/build/outputs/apk/**/**/*.apk
formulus/android/app/build/outputs/bundle/release/*.aab
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49 changes: 49 additions & 0 deletions formulus/android/ANDROID_RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Android release: Google Play and F-Droid

Formulus ships from one FOSS codebase. Play Store and F-Droid use the same dependency patches and build steps; only packaging and version-code handling differ.

## Shared release prep

1. Bump `versionName` / `versionCode` in `app/build.gradle` (or run `pnpm run sync:version` from `formulus/`).
2. From `formulus/`:
```sh
pnpm install --frozen-lockfile
pnpm run vendor:notifee
pnpm run patch:android-foss
pnpm run generate
```
3. Tag the release commit on the upstream repo, e.g. `v1.0.2` (F-Droid update checks use stable tags matching `v[\d.]+$`).

## Google Play

- **Artifact:** Android App Bundle (AAB) — `./gradlew bundleRelease` in `formulus/android/`.
- **CI:** GitHub Actions builds `bundleRelease` on `main`, `dev`, and GitHub Releases; uploads the AAB artifact and attaches it to releases.
- **versionCode:** Uses `defaultConfig.versionCode` in the AAB (single code per release).
- **Signing:** See [SIGNING_CONFIG.md](./SIGNING_CONFIG.md). CI uses repository secrets; local builds use `android/local.properties`.

Optional split APKs for sideloading or GitHub Release assets:

```sh
./gradlew assembleRelease
```

Split APKs use per-ABI version codes: `baseVersionCode + abiOffset` (2–5 when base is 2).

## F-Droid

- **Artifact:** One APK per ABI, built from source by F-Droid.
- **Metadata:** `fdroiddata/metadata/org.opendataensemble.formulus.yml` — four builds with `abiFilters` and explicit `versionCode` per ABI.
- **Gradle:** Pass `-PabiFilters=<abi>`; F-Droid prebuild strips custom APK naming and sets `versionCode = $$VERCODE$$`.
- **Init steps:** Same as shared prep above (`vendor:notifee`, `patch:android-foss`, `generate`).

After tagging, update the metadata commit SHA and version fields, then open/update the fdroiddata merge request.

## Version codes

| Channel | versionCode |
|---------|-------------|
| Play AAB | `defaultConfig.versionCode` |
| Play / local split APKs | base + ABI offset (armeabi-v7a +0, arm64-v8a +1, x86 +2, x86_64 +3) |
| F-Droid per-ABI build | Set in metadata prebuild (`$$VERCODE$$`) |

When bumping a release, increase `defaultConfig.versionCode` and update F-Droid build entries (and `CurrentVersionCode`) to match the highest per-ABI code.
8 changes: 5 additions & 3 deletions formulus/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ def enableProguardInReleaseBuilds = false
*/
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'

def abiVersionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
def perAbiVersionCode(int baseVersionCode, String abi) {
def offsets = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
return baseVersionCode + offsets.get(abi, 0) - 1
}

android {
ndkVersion = rootProject.ext.ndkVersion
Expand Down Expand Up @@ -158,8 +161,7 @@ android {
variant.outputs.each { output ->
def abi = output.getFilter(com.android.build.OutputFile.ABI)
if (abi != null) {
output.versionCodeOverride =
(100 * defaultConfig.versionCode) + abiVersionCodes.get(abi, 0)
output.versionCodeOverride = perAbiVersionCode(defaultConfig.versionCode, abi)
}
}
}
Expand Down
Loading