Pushing a v* tag builds the normal and FOSS APKs, signed with the upload key, and attaches them to a Gitea release; a manual run on a branch uploads a test build to the repo's packages. Everything runs on the Gitea server: a builder image with the Android SDK, an act_runner registered only for this repo, and plain shell steps (no third-party actions). The build itself is apps/mobile/scripts/build-android.sh, the same script for hand builds. Setup steps are in docs/ANDROID-CI.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.5 KiB
Building the Android app on the Gitea server
Pushing a version tag builds both APKs on our own server and attaches them to a Gitea release:
musicshare-<version>.apk: the normal app.musicshare-<version>-foss.apk: no closed-source code, the same build F-Droid makes. The build fails if any Google ML Kit or Play Services code ends up inside.
Both are signed with the upload key, and SHA256SUMS lists their checksums. Nothing leaves the server except the
downloads the build itself needs (npm packages, Gradle and its plugins).
The pieces:
| File | What it is |
|---|---|
.gitea/workflows/android.yml |
The workflow. It uses only plain shell steps, no third-party actions. |
apps/mobile/scripts/build-android.sh |
The build. You can also run it by hand on any machine with the Android SDK. |
deploy/android-builder/Dockerfile |
The build environment: Node 22, Java 17 and the Android SDK/NDK. |
deploy/gitea-runner/ |
The runner (act_runner) that runs builds on the server. |
One-time setup (on the Gitea server)
The server needs about 8 GB of free memory during a build and about 15 GB of disk for the image and caches. A first build takes 30-40 minutes; later ones reuse the Gradle cache.
-
Turn on Actions if it's off. In Gitea's
app.ini, set:[actions] ENABLED = trueRestart Gitea. Then, in the repo, go to Settings > Repository > Actions and enable it.
-
Build the builder image from a checkout of this repo:
docker build -t musicshare-android-builder deploy/android-builderRebuild it when React Native's SDK or NDK versions change (the Dockerfile says where to look).
-
Start the runner. In the repo, open Settings > Actions > Runners > Create new runner and copy the token. Use the repo's page, not the site admin's, so the runner only takes this repo's jobs. Then:
cd deploy/gitea-runner RUNNER_TOKEN=<token> docker compose up -dIt registers once (saved in
./data), then shows as idle with the labelmusicshare-android. The runner controls Docker on the host, so treat it like root access. The workflow only runs for tags and manual runs, never for pull requests. -
Add the secrets under Settings > Actions > Secrets:
UPLOAD_KEYSTORE_BASE64: the output ofbase64 -w0 ~/.config/musicshare/musicshare-upload.jks.UPLOAD_STORE_PASSWORD,UPLOAD_KEY_ALIAS(musicshare-upload),UPLOAD_KEY_PASSWORD: the values in~/.gradle/gradle.propertieson the machine you've been building on.RELEASE_TOKEN: create it under User settings > Applications > Access tokens, with write:repository and write:package permissions.
Releasing
- Bump
versionandandroid.versionCodeinapps/mobile/app.json. Addfastlane/metadata/android/en-US/changelogs/<versionCode>.txt, then commit. - Tag and push:
git tag v1.1.0 && git push origin main v1.1.0. - Watch it under the repo's Actions tab. The APKs appear on the Releases page.
The build refuses to run if the tag doesn't match the version in app.json. Re-running a tag's build replaces
that release's files.
Test builds: go to Actions > Android > Run workflow and pick a branch. The APKs go to the
repo's Packages as musicshare-android, versioned <branch>-<commit>, instead of to a release.
Building by hand
apps/mobile/scripts/build-android.sh # APKs in apps/mobile/dist
It uses the upload key from ~/.gradle/gradle.properties if it's there; otherwise the APKs come out unsigned.