Add F-Droid publishing guide and self-hosted repo helper script
docs/FDROID.md covers both a self-hosted F-Droid repo and the official f-droid.org route (incl. the prebuilt-OpenCV caveat). scripts/update-fdroid-repo.sh pulls the release APKs from Gitea and rebuilds the signed index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
106
docs/FDROID.md
Normal file
106
docs/FDROID.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Publishing PaperScan on F-Droid
|
||||||
|
|
||||||
|
Two routes, from easiest to most reach:
|
||||||
|
|
||||||
|
1. **Your own F-Droid repository** — you host your signed APKs; users add your repo URL.
|
||||||
|
2. **The official f-droid.org repository** — huge reach, but they build from source and vet
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
Both use the store metadata in [`fastlane/metadata/android/`](../fastlane/metadata/android).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Your own F-Droid repository (recommended first)
|
||||||
|
|
||||||
|
You serve a small static site containing your signed APKs plus a signed index. Users add the
|
||||||
|
URL once in the F-Droid app and then get updates automatically. No review, no rebuild, and the
|
||||||
|
prebuilt OpenCV libraries are a non-issue because *you* provide the APK.
|
||||||
|
|
||||||
|
### One-time setup
|
||||||
|
|
||||||
|
Install `fdroidserver` (needs a JDK + the Android SDK build-tools on `PATH`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pipx install fdroidserver # or: sudo apt install fdroidserver
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the repo workspace and its **repo signing key** (separate from the app signing key —
|
||||||
|
it signs the index, not the app):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export FDROID_HOME="$HOME/paperscan-fdroid"
|
||||||
|
mkdir -p "$FDROID_HOME" && cd "$FDROID_HOME"
|
||||||
|
fdroid init # generates config.yml + keystore.p12
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `config.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
repo_url: "https://fdroid.geyskens.eu/repo" # where you'll host it
|
||||||
|
repo_name: "PaperScan"
|
||||||
|
repo_description: "Self-hosted F-Droid repository for PaperScan."
|
||||||
|
archive_older: 3 # keep last 3 versions in the main repo
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ Back up `keystore.p12` and its passwords (in `config.yml` / `~/.config/fdroidserver`).
|
||||||
|
Lose it and you must publish a **new** repo URL — clients can't verify updates otherwise.
|
||||||
|
|
||||||
|
Let F-Droid pick up the localized store text: point it at this repo's fastlane metadata:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p "$FDROID_HOME/metadata"
|
||||||
|
ln -s /path/to/paperscan/fastlane/metadata/android "$FDROID_HOME/metadata/eu.geyskens.pdfscan"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publishing a version
|
||||||
|
|
||||||
|
Use the helper script (pulls every release APK from Gitea and rebuilds the index):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
FDROID_HOME="$HOME/paperscan-fdroid" /path/to/paperscan/scripts/update-fdroid-repo.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then publish the generated `repo/` directory to your web host, e.g.:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rsync -a --delete "$FDROID_HOME/repo/" web:/var/www/fdroid/repo/
|
||||||
|
```
|
||||||
|
|
||||||
|
Serve it as plain static files (any web server). Users then:
|
||||||
|
**F-Droid app → Settings → Repositories → + → `https://fdroid.geyskens.eu/repo`**, and enable it.
|
||||||
|
Tip: `https://fdroid.geyskens.eu/repo?fingerprint=<FINGERPRINT>` (from `fdroid update` output)
|
||||||
|
lets them add it with the fingerprint pre-filled.
|
||||||
|
|
||||||
|
### Automating it in CI (optional)
|
||||||
|
|
||||||
|
The existing Gitea Actions build already produces a signed APK per tag. To also refresh the
|
||||||
|
F-Droid repo, add a job that: installs `fdroidserver`, restores the **repo** keystore from a
|
||||||
|
secret, runs `scripts/update-fdroid-repo.sh`, and `rsync`es `repo/` to the web host (host key +
|
||||||
|
key as secrets). Keep the repo keystore in a secret just like the app signing key.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. The official f-droid.org repository
|
||||||
|
|
||||||
|
Bigger audience (it's in the default F-Droid app), but stricter:
|
||||||
|
|
||||||
|
- **License** — must be a recognized free license. PaperScan is GPL-3.0 ✔ (`LICENSE`).
|
||||||
|
- **Build from source** — F-Droid builds the APK on their servers; no prebuilt binaries in the
|
||||||
|
APK's own code. ⚠️ Our `org.opencv:opencv` Maven dependency ships **prebuilt native `.so`
|
||||||
|
libraries**. F-Droid flags prebuilt binaries; you may need to build OpenCV from source or get
|
||||||
|
the artifact allow-listed. This is the main hurdle — resolve it before submitting.
|
||||||
|
- **Reproducible-ish, no trackers** — PaperScan already has no analytics/trackers and only the
|
||||||
|
Camera + Internet permissions, which helps.
|
||||||
|
|
||||||
|
Process:
|
||||||
|
|
||||||
|
1. Open a **Request For Packaging (RFP)** issue at
|
||||||
|
`https://gitlab.com/fdroid/rfp` (or go straight to a merge request).
|
||||||
|
2. Add a build recipe `metadata/eu.geyskens.pdfscan.yml` to the `fdroiddata` repo describing the
|
||||||
|
source (`git.geyskens.eu`), the tag, and the Gradle build. The fastlane metadata is picked up
|
||||||
|
automatically for the listing.
|
||||||
|
3. Iterate with the F-Droid maintainers (mostly around the OpenCV native libs).
|
||||||
|
|
||||||
|
Because F-Droid builds from source, they also **re-sign** the APK with F-Droid's key — so an app
|
||||||
|
installed from f-droid.org can't be updated from your own repo and vice-versa (different
|
||||||
|
signatures). That's expected; pick one channel per user.
|
||||||
45
scripts/update-fdroid-repo.sh
Executable file
45
scripts/update-fdroid-repo.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Rebuilds a self-hosted F-Droid repo for PaperScan: downloads every release APK
|
||||||
|
# from the Gitea repository and regenerates the (signed) index.
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# * fdroidserver installed (`pipx install fdroidserver`)
|
||||||
|
# * `fdroid init` run once in $FDROID_HOME (creates config.yml + keystore)
|
||||||
|
# * JDK + Android SDK build-tools on PATH
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# FDROID_HOME=~/paperscan-fdroid ./scripts/update-fdroid-repo.sh
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
FDROID_HOME="${FDROID_HOME:-$HOME/paperscan-fdroid}"
|
||||||
|
GITEA_API="${GITEA_API:-https://git.geyskens.eu/api/v1/repos/sam/paperscan}"
|
||||||
|
|
||||||
|
if [ ! -f "$FDROID_HOME/config.yml" ]; then
|
||||||
|
echo "No F-Droid repo at $FDROID_HOME. Run 'fdroid init' there first (see docs/FDROID.md)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$FDROID_HOME/repo"
|
||||||
|
cd "$FDROID_HOME"
|
||||||
|
|
||||||
|
echo "Fetching release APK list from Gitea…"
|
||||||
|
curl -fsSL "$GITEA_API/releases?limit=50" \
|
||||||
|
| python3 -c "import sys,json;[print(a['browser_download_url']) for r in json.load(sys.stdin) for a in r.get('assets',[]) if a['name'].endswith('.apk')]" \
|
||||||
|
| while read -r url; do
|
||||||
|
dest="repo/$(basename "$url")"
|
||||||
|
if [ -f "$dest" ]; then
|
||||||
|
echo " have $(basename "$url")"
|
||||||
|
else
|
||||||
|
echo " get $(basename "$url")"
|
||||||
|
curl -fsSL "$url" -o "$dest"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Rebuilding index…"
|
||||||
|
fdroid update --create-metadata --pretty
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done. Publish the repo, e.g.:"
|
||||||
|
echo " rsync -a --delete \"$FDROID_HOME/repo/\" web:/var/www/fdroid/repo/"
|
||||||
Reference in New Issue
Block a user