# 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-.apk`: the normal app. - `musicshare--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. The caches are Docker volumes, which live wherever Docker keeps its data (usually `/var/lib/docker`). Check that disk has room (`df -h /var/lib/docker`): if it fills up, everything else using Docker on the server, including databases, stops writing. 1. **Turn on Actions** if it's off. In Gitea's `app.ini`, set: ```ini [actions] ENABLED = true ``` Restart Gitea. Then, in the repo, go to **Settings > Repository > Actions** and enable it. 2. **Build the builder image** from a checkout of this repo: ```bash docker build -t musicshare-android-builder deploy/android-builder ``` Rebuild it when React Native's SDK or NDK versions change (the Dockerfile says where to look). 3. **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: ```bash cd deploy/gitea-runner RUNNER_TOKEN= docker compose up -d ``` It registers once (saved in `./data`), then shows as idle with the label `musicshare-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. 4. **Add the secrets** under **Settings > Actions > Secrets**: - `UPLOAD_KEYSTORE_BASE64`: the output of `base64 -w0 ~/.config/musicshare/musicshare-upload.jks`. - `UPLOAD_STORE_PASSWORD`, `UPLOAD_KEY_ALIAS` (`musicshare-upload`), `UPLOAD_KEY_PASSWORD`: the values in `~/.gradle/gradle.properties` on 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 1. Bump `version` and `android.versionCode` in `apps/mobile/app.json`. Add `fastlane/metadata/android/en-US/changelogs/.txt`, then commit. 2. Tag and push: `git tag v1.1.0 && git push origin main v1.1.0`. 3. 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 `-`, instead of to a release. ## Building by hand ```bash 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.