Skip to content

Latest commit

 

History

History
129 lines (95 loc) · 5.67 KB

File metadata and controls

129 lines (95 loc) · 5.67 KB

F-Droid Release Architecture

This document explains how Session's F-Droid distribution works, why a custom script is needed, and how to perform the F-Droid release manually if the script is unavailable or broken.


Background: how F-Droid works

F-Droid is an open-source app store for Android. Unlike the Play Store, it operates on a repository model: a repo is a directory of APKs and a signed index file that F-Droid clients download to discover available apps and versions.

There are two ways an app can appear in F-Droid:

  1. Official F-Droid repo — F-Droid builds the APK itself from source, using its own signing key. The app developer has no control over the signing key or build timing.
  2. Self-hosted repo — The developer hosts their own F-Droid-compatible repository, signs the APKs and the repo index with their own keys, and F-Droid clients add it as a custom repo source.

Session uses a self-hosted repo at session-foundation/session-fdroid. This gives us control over the signing key and release timing, at the cost of needing to maintain the repo ourselves.


Why a custom script is needed

The standard fdroid command-line tools are designed around a workflow where F-Droid builds the APK from source. Because we sign APKs ourselves (to keep the signing key private) and provide pre-built APKs, the standard workflow does not apply cleanly.

Our script bridges that gap by:

  1. Building and signing the APK with Gradle, using our own keystore — fdroid update only indexes and re-signs the repo index, it does not build or sign APKs itself.
  2. Managing APK inventory — F-Droid clients expect old versions to remain available for users who cannot upgrade immediately. The script maintains a rolling window of the last four releases, removing anything older.
  3. Keeping secrets out of the repoconfig.yml (which contains keystore paths and passwords) and the generated metadata/<package-id>.yml (which embeds the current version code) are derived from committed template files (.tpl) at release time and deleted afterwards. Neither sensitive file is ever committed.
  4. Automating the PR workflow — the session-fdroid repo uses a PR-based flow so that every release update is reviewed by a human before it reaches users. The script handles branch creation and PR opening automatically.

Repository structure of session-fdroid

session-fdroid/
├── fdroid/
│   ├── repo/                          # APKs served to F-Droid clients
│   │   └── session-<version>-<abi>.apk
│   ├── metadata/
│   │   └── <package-id>.yml.tpl       # Template; .yml is generated at release time
│   ├── config.yml.tpl                 # Template; config.yml is generated at release time
│   └── index-v1.jar / index-v2.json   # Signed repo index, regenerated by `fdroid update`

The .tpl files are committed to the repo. The generated config.yml and metadata/<package-id>.yml are produced locally, used by fdroid update, then deleted — they are never committed.


How to publish a release using fdroidserver

Our script automates the steps below, but understanding them means you can recover from a broken script and reason about what the tooling is doing.

The core tool is fdroid update from the fdroidserver package. Its job is to:

  • Scan the APKs in repo/
  • Read the app metadata from metadata/<package-id>.yml
  • Produce a signed repository index (index-v1.jar and index-v2.json) that F-Droid clients download to learn what versions are available and where to get them

fdroid update does not build or sign APKs — it only indexes pre-built ones and signs the repo index using the key configured in config.yml.

config.yml

config.yml tells fdroid update how to sign the repo index and where to find the Android SDK. The key fields are:

repo_keyalias: <alias>
keystore: /path/to/repo-signing-keystore.p12   # PKCS12 format
keystorepass: <keystore-password>
keypass: <key-password>
android_sdk_path: /path/to/android/sdk

This file contains secrets and is never committed. In session-fdroid it is generated from config.yml.tpl at release time and deleted after fdroid update runs.

metadata/.yml

F-Droid uses a metadata file per app to describe the app to clients — its name, description, links, and crucially the CurrentVersionCode, which tells F-Droid clients which version is the latest so they know when to prompt for an upgrade.

The full metadata format is documented at https://f-droid.org/en/docs/Build_Metadata_Reference/

In session-fdroid, only the CurrentVersionCode field changes between releases. The rest of the file is static and lives in metadata/<package-id>.yml.tpl. The .tpl is rendered to .yml at release time with the new version code substituted in, used by fdroid update, then deleted.

Adding a new version

The fdroidserver workflow for adding a new version to a self-hosted repo is:

  1. Place the new signed APK(s) in the repo/ directory alongside existing ones.
  2. Update CurrentVersionCode in metadata/<package-id>.yml to the new version code.
  3. Run fdroid update from the repo root (where config.yml lives). It will scan all APKs, merge in the metadata, and rewrite the signed index files.
  4. Commit the updated index files and new APKs (but not config.yml or the rendered metadata/<package-id>.yml).

When master of session-fdroid is updated, any F-Droid client that has added our repo will pick up the new index on its next refresh and offer the update to users.