最近我把自己好几年前的开源 Android 项目 WakeUpScreen 提交到了 F-Droid。整个流程其实并不算复杂,但第一次做的时候很容易搞错。这篇文章把完整的流程梳理一遍,包括我自己踩过的坑,希望对同样想把开源 Android 应用送上 F-Droid 的开发者有所帮助。
聊具体步骤之前,先回答一个问题:已经有 Google Play 了,为什么还要 F-Droid?
F-Droid 是一个完全由社区维护的开源 Android 应用商店,2010 年成立,目前收录了四千多款应用。它和 Google Play 在哲学上有几个根本性的差异:
适合 F-Droid 的应用大致有这样的画像:开源、不依赖 Google Play Services、注重用户隐私、希望在 Google Play 之外提供另一个分发渠道。WakeUpScreen 满足所有这些条件:GPL-3.0 协议、不需要联网、不申请网络权限、没有任何统计或广告 SDK。所以这次提交对我来说更像是一次「该做却一直没做」的事情终于补上的过程。
正式提交流程之前,需要先在自己的项目里做一些准备。
F-Droid 第一个会卡你的就是依赖。提交之前我做的第一件事是:
grep -rE "play-services|firebase|com\.google\.android\.gms" .
如果搜出任何匹配,那就是 F-Droid 红线。要么移除,要么这个应用只能被标记为有 anti-feature。
许可证方面,F-Droid 接受所有主流的 FOSS 协议(Apache 2.0、MIT、BSD、GPL 等),完整列表在 fdroiddata 仓库的 templates 目录 里。WakeUpScreen 用的是 GPL-3.0,没问题。
另外要检查依赖的库本身是不是 FOSS。WakeUpScreen 用到的几个第三方库都是允许的:com.tencent:mmkv(BSD)、com.blankj:utilcodex(Apache 2.0)、Glide(BSD)、AndroidX/Compose(Apache 2.0)。这部分大多数项目都不会有问题,注意一下统计/推送类的库就行(友盟、极光、百度统计这些通常都是闭源)。
F-Droid 会自动从你的项目里抓取应用描述、截图、changelog,前提是按照 fastlane 的标准结构 放在 fastlane/metadata/android/ 下面。这个目录长这样:
fastlane/metadata/android/
├── en-US/
│ ├── title.txt (≤ 50 字符)
│ ├── short_description.txt (≤ 80 字符,不要加句号)
│ ├── full_description.txt (≤ 4000 字符)
│ ├── changelogs/
│ │ └── 30300.txt (文件名必须是 versionCode)
│ └── images/
│ ├── icon.png (512 × 512)
│ └── phoneScreenshots/
│ ├── 1.png
│ └── 2.png
├── zh-CN/
│ └── ...
└── it/
└── ...
有几个细节容易踩:
en-US/ 也行。3.0.3 但 versionCode 是 30300,文件就得叫 30300.txt。这一点 fastlane 文档讲得不够清楚,第一次很容易写错。ic_launcher-web.png,那个文件天然就是这个尺寸。我把 WakeUpScreen 现成的 screenshots/ 目录里的图复用了一下,描述文本则是从 README 提炼的,三种语言(英文、中文、意大利语)都有对应的 README,搬运起来也就是十几分钟的事。
这一步是可选的,但强烈推荐。后面提交 F-Droid 的时候,需要从签名 APK 提取一个 SHA-256 cert 指纹填到 yml 里。如果你有一个 GitHub Actions 工作流自动产生签名 APK 并推到 Releases,这一步就只是 gh release download + apksigner verify 两条命令。否则你得自己在本地折腾 keystore、签名、上传,工作量不小。
我的 release.yml 监听的是 gradle.properties 里 AppVersionName 字段的变化:每次它变,工作流就用 secrets 里存的 keystore 构建一份签名 APK,自动打 tag、自动创建 GitHub Release。这样我每次发版只要改一行版本号,剩下的全自动,对 F-Droid 提交流程也很友好。
正式的提交流程分四步:fork fdroiddata 仓库、写 metadata yml、本地验证构建、提交 MR。
F-Droid 的所有应用元数据都维护在 fdroid/fdroiddata 这个仓库里。注意是 GitLab,不是 GitHub。F-Droid 项目从早期就把所有的 infrastructure 放在 GitLab 上,原因之一是 GitLab 自己也是开源软件,和 F-Droid「一切都应当自由」的理念一致。如果你之前一直只用 GitHub,这里需要稍微调整一下心理预期:接下来的所有操作都在 gitlab.com 上进行。
所以提交流程的第一步是注册一个 GitLab 账号(如果你还没有的话)。访问 gitlab.com/users/sign_up 即可,可以用邮箱注册,也可以直接用 GitHub OAuth 登录,后者其实挺方便,相当于你的 GitHub 账号顺手多了一个 GitLab 镜像身份。注册过程和 GitHub 几乎一样,没什么坑。
注册好之后,访问 gitlab.com/fdroid/fdroiddata,点击右上角的 Fork 按钮,把这个仓库 fork 到你自己的账号下。这是一个标准的 fork & MR 工作流:你在自己的 fork 里改,然后向上游 fdroiddata 提 Merge Request(GitLab 的 MR 等同于 GitHub 的 PR)。第一次 fork 的时候 GitLab 会问你 fork 到哪个 namespace,选你自己的用户名即可。
fork 完成后,把它 clone 到本地,开新分支,拷贝模板:
# clone 你刚 fork 出来的仓库(注意把 <你的用户名> 替换成你的 GitLab 用户名)
git clone --depth=1 [email protected]:<你的用户名>/fdroiddata.git
cd fdroiddata
# 为你的应用建分支(分支名 = applicationId)
git checkout -b com.example.myapp
# 拷贝模板
cp templates/build-gradle.yml metadata/com.example.myapp.yml
注意分支名和 yml 文件名都是你的 applicationId(build.gradle 里的 applicationId 字段,也就是 package name),不是项目的英文名。比如 WakeUpScreen 的 applicationId 是 com.symeonchen.wakeupscreen,那么分支名和 yml 文件名都得是 com.symeonchen.wakeupscreen。
这是整个流程里最容易出错的一步。下面是我给 WakeUpScreen 写的 yml,把每个字段的意思都标注一下:
Categories:
- System
License: GPL-3.0-only
AuthorName: riko
AuthorEmail: [email protected]
WebSite: https://riko2chen.github.io/WakeUpScreen/
SourceCode: https://github.com/riko2chen/WakeUpScreen
IssueTracker: https://github.com/riko2chen/WakeUpScreen/issues
Changelog: https://github.com/riko2chen/WakeUpScreen/blob/HEAD/docs/CHANGELOG.md
AutoName: WakeUpScreen
RepoType: git
Repo: https://github.com/riko2chen/WakeUpScreen.git
Builds:
- versionName: 3.0.3
versionCode: 30300
commit: 456b21655618b0baffc27328e01199aa2c2f9a28 # 完整 commit hash,不要用 tag 名
subdir: app # build.gradle 所在的子目录
gradle:
- yes # 用默认的 gradle flavor
AllowedAPKSigningKeys: <SHA-256 cert 指纹,小写无空格>
AutoUpdateMode: Version
UpdateCheckMode: Tags
CurrentVersion: 3.0.3
CurrentVersionCode: 30300
几个关键字段值得展开:
Categories:F-Droid 的预设分类,常用的有 System、Connectivity、Internet、Multimedia 等。完整列表在 fdroiddata 的 config/categories.yml 里。
License:必须是 SPDX 标识符,比如 GPL-3.0-only 或 Apache-2.0,不能写成 GPL3 这种自定义形式。
Builds:可以列多个,对应每个 release 的 commit。F-Droid 会从这个 commit checkout 出来重新构建。commit 字段一定要写完整的 commit hash。tag 看着方便,但毕竟是可移动引用(git tag -f 一行命令就能改指向),hash 才是内容指纹,F-Droid 出于供应链安全只接受 hash。git rev-list -n 1 <tag> 即可拿到。第一次提交时只要写当前最新版本就行,之后由 AutoUpdateMode 自动追加(机器人会把新 tag 解析成 hash)。详见 4.5 节。
AllowedAPKSigningKeys:这是新增的安全字段,作用是限定只接受用这个 key 签名的 release,防止有人把恶意 APK 伪装成你的版本提交。提取方式:
# apksigner 在 Android SDK 的 build-tools 目录下
~/Library/Android/sdk/build-tools/35.0.0/apksigner verify --print-certs your-release.apk
# 找 "Signer #1 certificate SHA-256 digest:" 那一行的内容,去空格转小写
AutoUpdateMode + UpdateCheckMode:让 F-Droid 自动监听你的版本号变化,新版本一旦发布就自动收录。最常用的组合是 AutoUpdateMode: Version + UpdateCheckMode: Tags:F-Droid 遍历你的 git tag、checkout 出来用正则在 app/build.gradle 里找 versionCode <数字> 和 versionName "X.Y.Z"。这是开源应用最省心的配置。如果你的 build.gradle 是从 gradle.properties 用 property reference 读版本号(像 WakeUpScreen 这样),Tags 模式默认的 build.gradle 解析器看不懂 property。但有救:给 Tags 模式额外配一个 UpdateCheckData,让 F-Droid 改读 gradle.properties。我在 4.1 节走了一段弯路最后选了 HTTP,4.5 节才在 review 中学到 Tags + 自定义 UpdateCheckData 是更地道的写法。
Changelog:F-Droid 推荐用 /HEAD/ 而不是 /master/ 或 /main/ 来指向默认分支的文件。fdroid lint 会主动 flag 这个。
本地验证分两层:轻量的 lint / checkupdates / rewritemeta(一定要跑),和重量的 fdroid build(Apple Silicon 用户基本跑不起来,下面 4.2 节会展开)。
轻量验证不需要 Docker,几秒钟就能跑:
brew install fdroidserver
cd ~/Project/fdroiddata
fdroid readmeta
fdroid rewritemeta com.example.myapp # 让 yml 格式定型,必跑
fdroid lint com.example.myapp
fdroid checkupdates --allow-dirty com.example.myapp
rewritemeta 会按照 F-Droid 的格式规范重排你的 yml(给长字段换行、规范缩进等)。第一次提交一定要跑,否则 CI 会报「files need rewritemeta」(4.3 节有具体例子)。lint 检查 yml 字段完整性、URL 规范、类别合法性等。报错根据提示修。checkupdates 验证你的 UpdateCheckMode 配置能不能正确发现新版本。如果报「Couldn’t find any version information」,看 4.1 节。完整的 fdroid build 会用 F-Droid 的官方 Docker 镜像 registry.gitlab.com/fdroid/fdroidserver:buildserver 复现整个编译过程,命令大概长这样:
git clone --depth=1 https://gitlab.com/fdroid/fdroidserver ~/fdroidserver
docker run --rm -itu vagrant --entrypoint /bin/bash \
-v ~/Project/fdroiddata:/build:z \
-v ~/fdroidserver:/home/vagrant/fdroidserver:Z \
registry.gitlab.com/fdroid/fdroidserver:buildserver
进入容器后:
. /etc/profile
export PATH="$fdroidserver:$PATH" PYTHONPATH="$fdroidserver"
export JAVA_HOME=$(java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | awk -F'=' '{print $2}' | tr -d ' ')
cd /build
fdroid build -v -l com.example.myapp
跑通了基本就稳。跑不通的话常见原因:构建过程中下载外部资源(F-Droid 是离线构建)、NDK / JDK 版本不匹配、proguard 规则依赖闭源库等。
但如果你在 Apple Silicon 上:这个 Docker 镜像只有 amd64 版本,本地几乎跑不动。F-Droid 自己的 CI 跑在 amd64 runner 上,提交后 CI 会帮你跑。详见 4.2 节,那边讲了为什么这是「跳过 build 也 OK」的事。
提 MR 之前先去 RFP 仓库搜一下你的应用名。F-Droid 有一个专门的 Request For Packaging 仓库,让用户向 F-Droid 申请「希望某个开源应用被收录」。很可能你的应用早就被某个用户提过 RFP,issue 还开着。我搜「wakeupscreen」的时候发现 rfp#2023 “New APP: WakeUpScreen” 是 2022 年另一个用户提的,开了两年没人 fulfill。在 MR description 里加一行 Closes rfp#2023,合并时会自动关掉这个老 issue,对 reviewer 也是个好消息:「这是个长期需求」。
搜的命令:
curl -sSL "https://gitlab.com/api/v4/projects/fdroid%2Frfp/issues?search=YOUR_APP_NAME&state=all" \
| python3 -m json.tool
或者直接到 https://gitlab.com/fdroid/rfp/-/issues 用搜索框找。
然后正式提 MR:
git add metadata/com.example.myapp.yml
git commit -m "New App: com.example.myapp"
git push origin com.example.myapp
push 完 GitLab 会在终端打印一个创建 MR 的链接,直接点开。在 GitLab 创建页面上要做两件事:
fdroid/fdroiddata 的 master提完之后会触发 GitLab CI 跑一系列检查(lint、rewritemeta、build)。如果失败,CI 的日志会告诉你原因,4.3 节有一个我自己撞的具体例子。
CI 全过之后就是等 review。F-Droid 的 packagers 会在几天到几周之内 review,期间可能会要求你修改 yml 或者解决构建问题。合并之后,下一次的 build cycle(每天一次)会自动构建、签名、发布到 f-droid.org。
文档里的流程是「一切顺利的情况」,实际上提交过程中我撞了好几次墙。把这些都写下来,也许能省你几个小时。
fdroid checkupdates 看不懂 gradle.properties 引用UpdateCheckMode: Tags 是最常见、最推荐的配置:F-Droid 服务器克隆你的仓库、遍历每个 git tag、用正则解析 app/build.gradle 找 versionCode/versionName。听起来很自然,但它要求 build.gradle 里这两行必须是字面量:
versionCode 30300 // ✅ 能识别
versionName '3.0.3' // ✅ 能识别
versionCode project.AppVersionCode // ❌ 识别不了
versionName project.AppVersionName // ❌ 识别不了
WakeUpScreen 的 release.yml 工作流依赖 gradle.properties 作为版本号唯一来源(改一行就能触发 CI 自动构建发版),所以 app/build.gradle 是用 property reference 读取的。第一次跑 fdroid checkupdates 报:
ERROR: Couldn't find any version information
fdroidserver/checkupdates.py 里负责解析的是个简单的 Python 正则,不会执行 Gradle,自然 resolve 不了 property reference。这是工具链的长期限制,不是 bug。
解决方案有三个:
build.gradle 把版本号硬编码:最简单但破坏现有 release 工作流,不划算UpdateCheckMode: None:关掉自动检测,每次发版手动加 build entry,能用但啰嗦UpdateCheckMode: HTTP:直接 hit gradle.properties 的 GitHub raw URL,用正则提取版本号我选了 3,最终配置长这样:
AutoUpdateMode: Version v%v
UpdateCheckMode: HTTP
UpdateCheckData:
https://raw.githubusercontent.com/riko2chen/WakeUpScreen/HEAD/gradle.properties|AppVersionCode=(\d+)|.|AppVersionName=([\d.]+)
UpdateCheckData 的格式是 <vercode_url>|<vercode_regex>|<vername_url>|<vername_regex>,第三个字段写 . 表示「跟第一个字段同 URL」。AutoUpdateMode: Version v%v 里的 v%v 是 git tag 命名 pattern:我的 tag 是 v3.0.3、v3.0.4 这样,所以前缀是 v。
这样配好之后,F-Droid 服务器每天会自动 hit raw URL、提取版本、追加 build entry、触发构建。我未来发版只要改 gradle.properties 一行,剩下全自动,连 fdroiddata 都不用碰。
F-Droid 文档强烈建议提交前用 Docker 跑一次 fdroid build 验证。我跟着做,结果发现:
brew install docker 只装了 CLI,没有 daemon。macOS 不像 Linux 有原生 Docker daemon,得用 Colima 或 Docker Desktop 提供 daemon。我装了 Colima(轻量、CLI、开源):brew install colima && colima start,之后 docker CLI 就能用了。注意 colima 不会自动注册 docker context,需要手动 docker context create colima --docker host=unix://$HOME/.colima/default/docker.sock && docker context use colima。
registry.gitlab.com/fdroid/fdroidserver:buildserver 镜像只有 amd64 一个版本。F-Droid 的 GitLab CI 跑在 saas-linux-small-amd64 runner 上,他们的 .gitlab-ci.yml 里也没有 buildx 多架构构建。所有 6 个 tag(buildserver、buildserver-bookworm、buildserver-trixie 等)我都查过 manifest,全是 single-arch amd64。这是 F-Droid infrastructure 的一个长期事实,不是 bug。
在 Apple Silicon 上跑 amd64 镜像意味着 QEMU 模拟,加上 Colima 默认 1.9 GB 内存对 Android 构建来说太小(Gradle 自己就要 2 GB heap),实际是「跑不起来」。
破解方法理论上是 colima delete && colima start --arch x86_64 --memory 8 --cpu 4,让整个 Colima VM 在 QEMU 里以 x86_64 跑,VM 内的容器原生执行。但镜像要重拉、构建要 30-60 分钟,且 Apple Silicon 上 QEMU 性能也就那样。
实用结论:Apple Silicon 用户的最优解是跳过本地 fdroid build,依赖 F-Droid 的 CI 验证。fdroid lint 和 fdroid checkupdates 在本地跑没问题(不需要构建环境),这两步过了就放心交 MR。F-Droid 服务器自己有 amd64 环境,他们会跑 build。在 MR description 里诚实说明「本地没跑 build,因为 buildserver 镜像 amd64-only 加 Apple Silicon,依赖 CI 验证」,packagers 完全接受。
fdroid rewritemeta 的本地版本和 CI 不一致提交后 CI 第一次失败,报错说 metadata 文件需要 rewritemeta:
These files need rewritemeta:
metadata/com.symeonchen.wakeupscreen.yml
These are the formatting issues:
- UpdateCheckData: https://raw.githubusercontent.com/riko2chen/WakeUpScreen/HEAD/gradle.properties|...
+ UpdateCheckData:
+ https://raw.githubusercontent.com/riko2chen/WakeUpScreen/HEAD/gradle.properties|...
CI 把我的 UpdateCheckData 行改成了 YAML block scalar 格式(值换到下一行,缩进 2 格),并要求我的文件跟它的输出 byte-by-byte 一致。这是 F-Droid 对 metadata 文件的格式强制规范,正常应该在本地跑 fdroid rewritemeta 之后再提交,让格式定型。
我本地跑 fdroid rewritemeta 之后才发现:brew 装的 fdroidserver 2.4.3 比 CI 用的版本更激进。它把 Changelog、AllowedAPKSigningKeys、UpdateCheckData 三个字段全部换行了,而 CI 那边只换行 UpdateCheckData。换行后的「字段名: + 值另起一行」格式还会带一个 trailing space,触发 fdroid lint 的 trailing-spaces warning。
最后的修法是:跑一次本地 rewritemeta,然后用 Python 脚本手动 unwrap 不该换行的字段(在我这是 Changelog 和 AllowedAPKSigningKeys),保留 UpdateCheckData 的 wrapped 格式。这样跟 CI 的输出对齐了,重新 push 后 CI 通过。
教训:
fdroid rewritemeta 让格式定型再 pushfdroid lint 报 trailing-space warning 在 wrapped 行上是正常的(warning 不阻塞,exit 0),不要试图修F-Droid 的 MR 模板里有一个 checkbox 「Enable Reproducible Builds」,注释里有这么一句话:
Do note that if you don’t enable reproducible build then the apk will be signed with our key so you can’t enable it later.
很关键的话,但解释得不够清楚。展开一下:
启用门槛真的不低:你要让本地构建和 F-Droid Linux 服务器的构建 byte-by-byte 一致,需要消除时间戳、统一路径、固定 ZIP entry 顺序等等一堆事,反复测试。Apple Silicon 上更难(环境差异更大)。
「永久性」指的是:不启用 → F-Droid 用他们的 key 签 → 已经下载的用户拿到的是这个签名 → 后来想启用 RB(用你的 key),已下载的用户没法升级(Android 拒绝跨签名升级)。唯一的破解办法是发一个新 applicationId,相当于换了应用。
对 WakeUpScreen 这种「设置简单、跨平台同步需求弱」的工具应用来说,第一次提交不启用是合理选择。F-Droid 上四千多个应用大部分都没启用 RB。如果你的应用是数据库类(密码管理、笔记),跨平台数据迁移是核心需求,那就值得啃下 RB,但建议单独一次集中精力做,而不是混在第一次提交里。
commit 用完整 hash,UpdateCheckMode 还是该选 TagsCI 全过、MR 提交完之后,F-Droid 的 packager 一天之内就 review 了。两条意见,把前面 4.1 节的「最终方案」彻底推翻。
第一条:Builds.commit 必须写完整的 commit hash。
我原来的 build entry 写的是 commit: v3.0.3,packager 直接说:
Don’t use tag in commit. Use the full commit hash instead.
原因是 tag 在 git 里是可移动引用:git tag -f v3.0.3 <另一个 commit> 一行命令就能让 v3.0.3 指向完全不同的代码。如果哪天我有意或无意移了 tag,F-Droid 下次构建出来的代码就可能跟当初 review 通过的版本完全两样。commit hash 则是内容指纹,永远固定,456b21655618b0baffc27328e01199aa2c2f9a28 唯一且永远地对应那一份代码。F-Droid 出于供应链安全要求所有 Builds.commit 字段都写完整 hash。
获取 hash 一行命令:
git rev-list -n 1 v3.0.3
# 或者从远程仓库查
git ls-remote https://github.com/riko2chen/WakeUpScreen.git refs/tags/v3.0.3
好消息是这件事只需要手动做一次。AutoUpdateMode: Version 配合 F-Droid 的 checkupdates 机器人之后,机器人在每次检测到新 tag 时会自己把 tag 解析成 hash 写进新的 build entry。我未来发版只要在 WakeUpScreen 仓库里打 tag,fdroiddata 这边的 build entry 是机器人自动追加的,连 commit hash 都不用我自己写。
第二条:UpdateCheckMode 应该用 Tags,而不是我在 4.1 里折腾出来的 HTTP。
这条更让我意外,因为 4.1 节的结论是「Tags 模式看不懂 gradle.properties property reference,所以只能用 HTTP」。packager 给的 suggestion 是:
AutoUpdateMode: Version
UpdateCheckMode: Tags
UpdateCheckData: gradle.properties|AppVersionCode=(\d+)|.|AppVersionName=([\d.]+)
注意这里的 UpdateCheckData 写的是仓库内的相对路径:F-Droid 会在每个 git tag 的 checkout 里去读这个文件。我之前一直以为 UpdateCheckData 只能配合 UpdateCheckMode: HTTP 使用,但其实 Tags 模式同样接受 UpdateCheckData:F-Droid 会遍历每个 git tag,在 tag 的 checkout 内用这个文件路径加正则提取版本号,既绕过了 build.gradle 的 property reference 问题,也不需要走 HTTP 拉远程文件。
回头看 4.1,错的根源是我当时只读了 fdroidserver 文档里 Tags 模式那一段,把「Tags 模式只能解析 build.gradle」这个错误结论当成了事实。Tags + 自定义 UpdateCheckData 才是 F-Droid 最推荐、最干净的方案。它仍然走 git tag 这条主路径(和 F-Droid 「从 tag 构建」的整体哲学一致),只是把版本号提取的细节交给我自己定义的正则。HTTP 模式相比之下既绕路又依赖 raw.githubusercontent.com 的可达性,属于次等方案。
修正后我的 yml 末尾就变成了:
Builds:
- versionName: 3.0.3
versionCode: 30300
commit: 456b21655618b0baffc27328e01199aa2c2f9a28
subdir: app
gradle:
- yes
AllowedAPKSigningKeys: 7044dcb7b20edcefdb22923e649c84187e3aa818fc3a58dfcb2eccc92cddef1c
AutoUpdateMode: Version
UpdateCheckMode: Tags
UpdateCheckData: gradle.properties|AppVersionCode=(\d+)|.|AppVersionName=([\d.]+)
教训:
Builds.commit 永远写完整 hash。F-Droid 的硬性安全要求,CI 不会拦但 reviewer 一定会指出UpdateCheckMode: Tags + 自定义 UpdateCheckData 是 gradle.properties property reference 项目的正解,比 HTTP 模式更简洁、更不依赖外部资源,也和 F-Droid「从 tag 构建」的整体哲学保持一致整个流程梳理下来,把一个开源 Android 应用上架 F-Droid 大致就是这几件事:
rewritemeta + lint + checkupdates 验证、提 MR相比 Google Play 那种「上传 APK → 审核 → 上线」的流程,F-Droid 多了「写 metadata → CI 跑通 → 等服务器构建」这几步,但好处是整个过程是公开的、可追溯的、永远开源的。F-Droid 服务器构建出来的 APK 用 F-Droid 的 key 签名,意味着即使开发者本人消失了,应用还是可以由社区维护下去。这一点在 Google Play 的世界里是无法想象的。
我觉得这种「再普通不过的开源软件分发渠道」,恰好是当下最稀缺的东西。Google Play 越来越像一个商业平台,App Store 从来就是一个商业平台,而 F-Droid 还坚持着 2010 年那种「软件应该自由」的初心。所以即使工作量稍大一点,把开源应用送一份到 F-Droid,是值得做的事。
F-Droid 首页上常年挂着一句口号:「Free as in freedom」。2010 年读这句话像理想主义宣言,2026 年再读更像一记警钟。Google 这两年在 Android 的开放性上不断踩刹车,所有上架开发者强制实名认证、应用签名托管走 Play App Signing、就连 sideload 安装也开始被纳入开发者注册体系,整个 Android 生态正在悄悄地从「开放平台」向「带闸的花园」迁移。在这个背景下,F-Droid 这样一个完全社区驱动、对开发者零门槛、对用户零追踪、永远开源的商店,越来越像稀有物种。把一款开源应用上架到 F-Droid 这件事本身,就已经是一种站队,给这个稀有物种多续一份口粮。
这篇文章是我为 WakeUpScreen 提交 F-Droid 过程中的实践记录,所有 yml 字段、命令和踩过的坑都来自真实经历。如果你正在做同样的事,欢迎在 GitHub issues 里交流。
If you have anything you'd like to discuss, any ideas you want to bounce around, please send me a message.