最近开发了一款好几年前就想做的应用,一个管理 2FA(两步验证)令牌的工具,叫做 Flauth ,基于 Flutter 开发,支持全平台。也已经发布到了 F-Droid 上,欢迎大家安装使用。
在如今 Agent 盛行的年代,开发这个软件本身没什么难度,大概 80% 的代码都是 Vibe 的,Dart 也是现学现卖,剩下的 20% 着重花在了设计与测试上,之所以想自己开发,主要是市面上没有同时满足以下三点需求的 App:
- 支持多平台,我目前主要用到 macOS、Linux、Android
- 开源,最起码要支持数据的导入、导出,并且是开放的格式,没有 Vendor Lock-in 的风险
- 支持自定义备份,毕竟数据在自己手上才是最安全的
Flauth 就是上述需求的产物,技术细节这里不多赘述,感兴趣的读者可以查看:Flauth 身份验证架构说明、备份与恢复逻辑、性能设计文档。
在小范围内测之后,功能已经完备,我也把 Authy 中的十几个令牌 一个个 (鄙视脸!)迁移过来,就准备发布到 F-Droid 上,之所以选择这个平台,主要是因为它是开源软件的集中地,用户群体也比较符合我的预期。但由于是第一次使用 F-Droid 发布应用,过程还是遇到了一些问题,花了一些时间才弄明白。这篇博客文章就来分享一下我的发布经验,希望能帮助到有类似需求的读者。
签名
在发布之前,需要对 apk 文件签名,这是 Android 应用发布的基本要求。出于安全考虑,应用开发者也需要签名,以防止应用被篡改。Sign the app 是 Flutter 的文档介绍。需要修改 build.gradle.kts 文件,添加签名配置:
| |
Android 签名指南是 Flauth 中的签名流程,供大家参考。还有一点需要注意,AGP 默认会插入一个额外的签名块(extra signing block), 叫做 Dependency metadata,用于存储一些依赖信息。但 F-Droid 要求应用不能包含这个签名块,否则会报错,需要在 build.gradle.kts 中添加如下配置::
| |
这样构建出来的 apk 文件就不会包含这个签名块了,这里有具体的原因解释。
文档
- Submitting to F-Droid Quick Start Guide
- Build Metadata Reference
- https://gitlab.com/fdroid/fdroiddata/blob/master/CONTRIBUTING.md
- https://gitlab.com/fdroid/wiki/-/wikis/Tips-for-fdroiddata-contributors/FOSS-libs
上面这些文档是官方提供的,涵盖了从准备元信息、编写 yaml 描述文件,到构建与提交的全过程,建议先浏览一遍,有个整体流程的概念。
元信息准备
为了在 F-Droid 上正确显示应用的信息,需要准备一些元信息,包括:图标、截图、描述文件、ChangeLog 等,这些需要放在项目中,目录结构如下:
$ tree metadata/
metadata/
└──en-US
├──full_description.txt
├──short_description.txt
├──title.txt
├──changelogs
│ └──2001.txt
└──images
├──icon.png
└──phoneScreenshots
├──1.png
├──2.png
└──3.png
full_description.txt:应用的完整描述short_description.txt:应用的简短描述title.txt:应用的标题changelogs/2001.txt:版本代码(versionCode)2001 的更新日志images/icon.png:应用图标,512x512 像素images/phoneScreenshots/:应用截图,建议提供多张,分辨率无要求,但建议至少 1080x1920 像素
yaml 描述文件
F-Droid 使用 yaml 文件来描述应用的构建信息,文件名一般为包名加上 .yml 后缀,比如我的应用包名是 =net.liujiacai.flauth=,那么文件名就是 net.liujiacai.flauth.yml。这个文件需要放在 F-Droid 的数据仓库中,一般不放在应用代码仓库中。templates 目录下有一些模板,可以参考。 #31694 是我提交的 MR,历时一周合入。
| |
Categories:分类,可以参考 官方文档 进行选择,我选择了Password & 2FA和Security。License:许可证类型,我选择了MIT。AuthorName、AuthorEmail、WebSite、SourceCode、IssueTracker:这些都是应用的基本信息,按实际填写即可。AutoName:应用的名称。RepoType和Repo:代码仓库类型和地址,我的应用托管在 GitHub 上,所以填写git和仓库地址。Binaries:预编译的二进制文件下载地址,我这里填写了 Android 版本的 apk 下载地址,%v会被替换为版本号,%c会被替换为版本号代码。这个需要配合后面的AllowedAPKSigningKeys一起使用,确保 apk 文件的签名正确。Builds:构建信息列表,每个版本对应一个条目,包含以下字段:versionName:版本名称versionCode:版本代码commit:对应的 git 提交哈希sudo:构建前需要执行的命令列表,这里我创建了工作目录并修改了权限。output:构建产物路径srclibs:需要使用的源代码库,这里我指定了 Flutter 的稳定版分支。rm:构建前需要删除的目录列表,我删除了不需要的平台目录。prebuild:构建前需要执行的命令列表,这里我设置了 Flutter 版本,获取依赖等。scandelete:扫描后需要删除的目录列表,我删除了.pub-cache目录。build:构建命令列表,这里我执行了 Flutter 的构建命令,需要注意的是,为了满足 reproducible build 的构建要求,这里对齐了 GitHub Actions 中的路径, 因为 Binaries 处指定的二进制就是从那里构建出来的。ndk:指定使用的 NDK 版本,这里我选择了r28c。
AllowedAPKSigningKeys:允许的 APK 签名密钥列表,我填写了我的签名公钥的 SHA-256 指纹。可以通过以下命令获取 apk 文件的签名指纹:1apksigner verify --print-certs flauth-android-arm64-v8a-v1.0.0.apkapksigner工具包含在 Android SDK 的 build-tools 目录下,可以参考 官方文档 进行使用。macOS 上的路径是:1~/Library/Android/sdk/build-tools/36.1.0/apksignerAutoUpdateMode:自动更新模式,我选择了Version。UpdateCheckMode:更新检查模式,我选择了基于标签的检查,正则表达式为^v[1-9].*,表示匹配以v开头,后面跟数字的标签,比如v1.0.0、v2.1.3等。VercodeOperation:版本代码操作,这里之所以需要这么做,是因为构建时使用了split-per-abi,会生成多个 apk 文件,好处是最终的 apk 体积变小。每个 apk 文件的版本代码需要不同,Flutter 会在 pubspec.yaml 中 versionCode 的基础上加 2000,比如是 1, 那么 arm64 架构就是 2001,其他架构可能会是 2002,根据实际调整就好,但 Android 手机一般现在都只需要 arm64 架构就够了。UpdateCheckData:更新检查数据,我指定了从pubspec.yaml文件中提取版本号和版本代码的正则表达式。CurrentVersion和CurrentVersionCode:当前版本号和版本代码,fdroid checkupdates --allow-dirty com.example命令会根据仓库中的最新版本自动更新这两个字段。
构建与提交
准备好上述文件之后,就可以开始构建与提交了。F-Droid 提供了一个 CI 环境,可以在其中进行构建和测试。具体的构建命令可以参考上面的 yaml 文件中的 prebuild 和 build 部分。
| |
在容器里面,可以运行以下命令进行构建:
| |
如果中途报错,可以根据日志进行修复,然后重新运行上面的命令即可。用 -v 参数可以看到更详细的日志。如果一切顺利,就可以给 F-Droid 提交 MR 了,这需要在 F-Droid 数据仓库 中创建一个 MR(在 gitlab 上),等待审核通过即可。
审核通过后,一般过一两天应用就会上线了,这时就可以通过 F-Droid 客户端进行安装和更新。