fdroidserver 2.4.5 常用 CLI 命令与工具详解

fdroid 2.4.5 命令族逐个实测详解:init/update/publish/gpgsign/deploy/verify/checkupdates/lint/signatures 等仓库管理命令与构建类命令边界,附真实回显,并完成密钥备份到新服务器恢复的迁移闭环。

F-DroidF-DroidAndroid2026/10/28

fdroidserver 2.4.5 常用 CLI 命令与工具详解

目标:把 fdroid 2.4.5 的命令族逐个讲清——每个子命令的用途、典型用法与 2026-10-28 真实服务器实测回显,并完成「密钥备份 → 新目录恢复 → 签名信任不变」的迁移闭环。环境准备见《Ubuntu 22.04 安装 fdroidserver 2.4.5 指南》,参数含义见《fdroidserver 2.4.5 配置参数详解》,生态背景见《F-Droid 介绍与选型指南》。

实测环境:Ubuntu 22.04,fdroidserver 2.4.5(PyPI,/usr/local/bin/fdroid),演示仓库 /root/repo-c1(org.fdroid.fdroid 2000052 + org.schabi.newpipe 998/999/997,archive_older: 1,仓库网页根 8149 端口)。

一、命令体系总览

fdroid --help 的完整命令清单(2.4.5 实测,共 19 个子命令):

usage: fdroid [<command>] [-h|--help|--version|<args>]

Valid commands are:
   build          Build a package from source
   init           Quickly start a new repository
   publish        Sign and place packages in the repo
   gpgsign        Add PGP signatures using GnuPG for packages in repo
   update         Update repo information for new packages
   deploy         Interact with the repo HTTP server
   verify         Verify the integrity of downloaded packages
   checkupdates   Check for updates to applications
   import         Extract application metadata from a source repository
   install        Install built packages on devices
   readmeta       Read all the metadata files and exit
   rewritemeta    Rewrite all the metadata files
   lint           Warn about possible metadata errors
   scanner        Scan the source code of a package
   signindex      Sign indexes created using update --nosign
   btlog          Update the binary transparency log for a URL
   signatures     Extract signatures from APKs
   nightly        Set up an app build for a nightly build repo
   mirror         Download complete mirrors of small repos

按职责可分四类(本文实测重点为仓库管理类——自建静态仓库的主力):

类别命令依赖
仓库管理init, update, publish, signindex, verify, lint, readmeta, rewritemeta, signatures, gpgsign, checkupdates, import, mirrorPython + JDK,无需完整 Android SDK
发布分发deploy, btlog, nightly, install视目标而定
源码构建build(配合 makebuildserver)完整 Android SDK + 构建虚拟机
源码扫描scanner源码目录

说明:makebuildserver(构建虚拟机准备工具)不在 fdroid 入口的 19 个子命令内,属于源码构建流水线的独立环节;本文环境未部署构建虚拟机,构建类命令以边界实测为主。

二、仓库生命周期三命令:init → update → publish

2.1 fdroid init —— 初始化仓库

在空目录生成 config.yml(含自动生成的签名密钥口令)与 keystore.p12。实测回显、生成物与密钥指纹已在安装篇 8.1 节逐字记录,此处不赘述;要点回顾:

Built repo based in "/root/repo-b1" with this config:
  Android SDK:			/opt/android-sdk
  Keystore for signing key:	keystore.p12
...
(EXIT 0;生成 config.yml 18446B、keystore.p12 4294B、repo/)

2.2 fdroid update —— 核心:扫描入库 + 生成签名索引 + 归档

仓库日常维护的主体命令,职责有三:

① 入库扫描:扫描 repo/ 目录中的 APK,--create-metadata 时为新应用生成骨架元数据:

$ fdroid update --create-metadata
INFO: Using /opt/android-sdk/build-tools/34.0.0/apksigner
WARNING: repo_icon "repo/icons/icon.png" does not exist! Check "config.yml".
INFO: Generated skeleton metadata for org.fdroid.fdroid
INFO: Creating signed index with this key (SHA256):
INFO: 10 D4 37 3F ...
INFO: Finished

② 归档执行:按 archive_older 在 repo/ 与 archive/ 间移动版本(双向移动实证与 keepversions 加倍规则见配置篇第四节):

INFO: Moving org.schabi.newpipe_998.apk from repo to archive
INFO: Moving org.schabi.newpipe_998.apk from archive to repo   # CurrentVersionCode 调整后反向搬回

③ 索引签名:生成 index-v1/index-v2 双格式索引并按仓库密钥签名打包。常用开关:

  • --nosign:只建索引不签名(配合定时构建场景),实测结尾仅两行:

    INFO: Committing indexes to binary_transparency
    INFO: Finished
    

    随后用 fdroid signindex 补签名(见 3.1)。

  • -v:详细模式,归档决策(DEBUG: Checking archiving ...)只在 -v 下可见。

2.3 fdroid publish —— 签名入库「无签名 APK」

与 update 的分工:update 处理已签名 APK 的索引;publish 处理 unsigned/ 目录里未签名的 APK——自动为「同应用同签名」的包生成/复用应用级密钥别名并签名放入 repo/。

实测一(unsigned/ 不存在时):

$ fdroid publish
INFO: Creating log directory
WARNING: No unsigned directory - nothing to do
(EXIT=1)

实测二(放入 unsigned/org.schabi.newpipe_997.apk,NewPipe 0.27.0,aapt 确认 versionCode='997' versionName='0.27.0'):

$ fdroid publish
INFO: 2 apps, 2 key aliases
INFO: Processing unsigned/org.schabi.newpipe_997.apk
INFO: Key alias: ee8807d2
INFO: Key does not exist - generating...
INFO: Published org.schabi.newpipe_997.apk
INFO: published list signing-key fingerprints
(EXIT=0)

实测产物与影响:

  1. repo/ 新增 org.schabi.newpipe_997.apk、.apk.idsig(APK 签名 v4 增量文件)与 signer-index.json/signer-index.jar(多签名者索引);
  2. 仓库密钥不变:ee8807d2 是 newpipe 应用的新签名别名,仓库索引仍用 fdroid-server 密钥签名(B3:0D:B8:DC:… 指纹不变);
  3. 随后的 fdroid update 按 archive_older: 1 把 997 移入 archive(INFO: Moving org.schabi.newpipe_997.apk from repo to archive),并打出 WARNING: repo_key_sha256 not in config.yml, setting it to ... 自动回填配置。

三、索引与签名校验命令

3.1 fdroid signindex —— 给未签名索引补签

配合 update --nosign 使用,实测:

$ fdroid update --nosign && fdroid signindex
INFO: Signed index in archive
INFO: Signed archive/index-v1.json
INFO: Signed archive/entry.json

3.2 fdroid verify —— 校验已下载文件的完整性

对本地文件做索引一致性校验,实测静默通过(VERIFY_EXIT=0),加 -v 可见它读取了配置:

$ fdroid verify -v
DEBUG: Reading 'config.yml'

3.3 fdroid signatures —— 提取 APK 签名证书

把 APK 的签名证书提取到 metadata/<appid>/signatures/<vc>/(实测生成 SCHABI_K.RSA、SCHABI_K.SF、MANIFEST.MF 三个文件)。两大用途:

  1. 固化「开发者签名指纹」白名单(publish 的 Key alias 机制依赖它);
  2. 触发归档保留数翻倍(keepversions ×2,实测与源码取证见配置篇第四节)。

3.4 fdroid gpgsign —— APK 分离 GPG 签名

前置:gpgkey 参数已配置(密钥生成与 config 联动见配置篇第五节)。实测:

$ fdroid gpgsign
INFO: Signed org.schabi.newpipe_998.apk
INFO: Signed org.schabi.newpipe_999.apk
INFO: Signed entry.json
INFO: Signed index-v1.json
INFO: Signed index-v2.json

repo/ 下生成 *.apk.asc,客户端可独立校验 PGP 签名。

四、元数据命令

4.1 readmeta / rewritemeta

  • readmeta:解析校验全部元数据,正常时静默(实测无输出、退出码 0);

  • rewritemeta:按当前格式规范重写元数据文件(字段排序、格式归一),实测:

    $ fdroid rewritemeta
    INFO: Rewriting 'org.fdroid.fdroid'
    INFO: Rewriting 'org.schabi.newpipe'
    

4.2 fdroid lint —— 元数据体检

实测暴露了两类问题(退出码 0,警告型):

$ fdroid lint
org.fdroid.fdroid: Categories 'repo-c1' is not valid
org.fdroid.fdroid: Unexpected license tag "Unknown"! Only use FSF or OSI approved tags from https://spdx.org/license-list
org.schabi.newpipe: Categories 'repo-c1' is not valid
org.schabi.newpipe: Unexpected license tag "Unknown"! Only use FSF or OSI approved tags from https://spdx.org/license-list

Categories 只认 f-droid.org 官方分类名,License 只认 SPDX 的 FSF/OSI 许可 ID——自建仓库也建议遵守,lint 干净的元数据将来向 f-droid.org 提交时免返工。

4.3 fdroid checkupdates —— 检查上游新版本

要求元数据目录是 git 仓库。实测非 git 目录直接崩(栈尾):

subprocess.CalledProcessError: Command '['git', 'status', '--porcelain']' returned non-zero exit status 128.

git init && git add -A && git commit 后恢复正常(逐应用处理):

$ fdroid checkupdates
INFO: Processing org.fdroid.fdroid
INFO: Processing org.schabi.newpipe

4.4 fdroid import —— 从源码仓库提取元数据

在应用源码目录执行,从构建文件反推元数据。实测无 gradle 工程时报错(退出码 0):

$ fdroid import
CRITICAL: No gradle project could be found. Specify --subdir?

4.5 fdroid scanner —— 源码追踪器扫描

用 SUSS 等签名库扫描源码中的已知追踪器。实测无 Builds 配方时运行于当前源码状态:

$ fdroid scanner org.schabi.newpipe
INFO: org.schabi.newpipe: no builds specified, running on current source state
INFO: Finished

五、分发与运维命令

5.1 fdroid deploy —— 多目标发布

按 config.yml 的部署参数把仓库推到各目标(rsync/SSH、git 镜像、云存储、本地副本)。行为实测与逐条取证在配置篇第六节:local_copy_dir 的 fdroid 后缀校验与 {repo, archive} 生成、servergitmirrors 的 bare 提交(fdroidserver git-mirror)与「必须 https://…git 形式」的坑、离线机语义(与 local_copy_dir 同设时跳过 git 镜像)。

5.2 fdroid mirror —— 下载小型仓库的完整镜像

把远端仓库完整拉到本地(适合给内网搭镜像站)。两个实测要点:

  1. 参数是仓库基址而非 repo 目录:传 http://10.89.73.2:8149/c1/repo 会拼出错误路径 404(.../c1/repo/repo/index-v1.jar,HTTPError 404 栈回显,EXIT=1);

  2. 传基址 http://10.89.73.2:8149/c1 成功——wget 式拉取 3 个 APK 共 34M:

    Downloaded: 3 files, 34M in 0.06s
    ERROR: no "icon" in org.fdroid.fdroid
    ERROR: no "icon" in org.schabi.newpipe
    (EXIT=0)
    

    骨架元数据无 icon 字段导致的两条 ERROR 不影响 APK 与索引下载(同配置篇 per_app_repos 的 icon 边界同源)。

5.3 fdroid btlog —— 二进制透明日志

  • 无参默认拉取 https://f-droid.org 的公开日志,本实验网络不可达(requests ConnectionError);
  • 指向自建仓库:fdroid btlog -u http://10.89.73.2:8149/c1 --git-repo /srv/fdroid-bt,目标目录需先 git init,否则 CRITICAL: "/srv/fdroid-bt" does not exist! Create it, or use --git-repo;成功后在该 git 目录生成 repo/archive 索引快照。
  • 与 binary_transparency_remote 参数的分工:update 只本地提交,推送远端走 btlog(配置篇第八节)。

5.4 fdroid nightly —— nightly 构建发布器

为自动化 nightly 构建准备发布配置(生成签名变量、配合 per_app_repos 分仓)。fdroid nightly --help 实测暴露关键开关:--keystore、--show-secret-var、--keep-private-keys、--no-deploy、--file、--no-checksum、--archive-older——它是 CI(如 GitLab CI)里签发 nightly APK 的配套工具,日常仓库维护用不到。

5.5 fdroid install —— 把构建产物安装到设备

通过 adb 把 repo 中构建好的 APK 安装到连接的设备,实测静默执行(I_EXIT=0,无设备连接时不做任何事)。开发调试场景工具。

六、构建类命令边界:fdroid build

从源码构建 APK 的入口,依赖完整 Android SDK 与 buildserver 构建虚拟机。本文环境(无构建虚拟机、元数据无 Builds 配方)实测其边界:

$ fdroid build org.schabi.newpipe
INFO: Creating build directory
CRITICAL: No apps to process.
(B_EXIT=0)

「No apps to process」的直接原因是元数据没有 Builds 配方——这正是仓库管理类与构建类的分界:只发布 APK 的仓库永远不会触碰 build;要复刻 f-droid.org「从源码构建」模式,才需要部署 SDK/NDK/buildserver 全套(见选型指南的架构分类)。

七、备份与恢复闭环(迁移实测)

仓库的全部信任状态浓缩在四个东西里:config.yml(口令)、keystore.p12(信任锚)、metadata/、APK 文件。实测完整迁移闭环:

① 打包(在仓库目录 /root/repo-c1 执行):

$ tar czf /srv/fdroid-backup.tgz config.yml keystore.p12 metadata repo/*.apk
$ ls -lh /srv/fdroid-backup.tgz
-rw-r--r-- 1 root root 25M Oct 28 14:50 /srv/fdroid-backup.tgz

② 恢复到全新目录 /root/repo-restore 并重建索引:

$ mkdir -p /root/repo-restore && tar xzf /srv/fdroid-backup.tgz -C /root/repo-restore
$ cd /root/repo-restore && fdroid update
WARNING: repo_icon "repo/icons/icon.png" does not exist, generating placeholder.
INFO: Committing indexes to binary_transparency
INFO: Finished

③ 签名指纹逐项比对(原仓库 vs 恢复仓库,keytool 输出):

/root/repo-c1:      82:67:9F:ED:6F:96:2F:2B:6D:6C:86:38:22:57:81:2D:E7:5E:A8:C1:00:1E:E5:85:26:7F:93:8E:5B:94:92:89
                    B3:0D:B8:DC:9D:FA:E4:66:98:69:A5:67:5B:C3:89:47:F9:EC:1A:DD:54:52:26:B3:E4:75:B1:BA:F6:85:4E:42
/root/repo-restore: 82:67:9F:ED:6F:96:2F:2B:6D:6C:86:38:22:57:81:2D:E7:5E:A8:C1:00:1E:E5:85:26:7F:93:8E:5B:94:92:89
                    B3:0D:B8:DC:9D:FA:E4:66:98:69:A5:67:5B:C3:89:47:F9:EC:1A:DD:54:52:26:B3:E4:75:B1:BA:F6:85:4E:42

两枚指纹(应用签名别名 ee8807d2 与仓库签名别名 fdroid-server)完全一致——只要备份四件套在手,任何新服务器都能无损接管同一仓库,客户端信任不受影响。这也是「仓库签名密钥必须异地备份」的实操依据。

八、命令速查表

命令一句话用途典型退出码/注意点
init初始化 config + 签名密钥EXIT 0;SDK ERROR 可忽略
update扫描 + 归档 + 签名索引日常核心;-v 看归档决策
publishunsigned/ APK 自动签名入库无 unsigned/ 时 EXIT 1
signindex给 --nosign 索引补签配合 update --nosign
verify校验本地仓库完整性静默通过
gpgsignAPK 分离 GPG 签名需 gpgkey 参数
signatures提取 APK 证书到 metadatakeepversions 加倍触发
lint元数据体检警告型,EXIT 0
readmeta解析校验元数据正常静默
rewritemeta重写元数据为规范格式逐应用 INFO
checkupdates检查上游新版本必须 git 仓库
import从源码反推元数据需 gradle 工程
scanner源码追踪器扫描需源码目录
deploy多目标发布参数见配置篇第六节
mirror完整下载小型仓库参数为基址非 repo 路径
btlog二进制透明日志--git-repo 目录需 git init
nightlynightly CI 发布配套生成签名变量
installadb 安装构建产物静默
build源码构建 APK无 Builds 配方即 No apps to process

九、参考与延伸阅读