Flatpak 应用打包完整教程 / 第 9 章:仓库管理
第 9 章:仓库管理
本章目标:掌握 Flatpak 仓库的管理,学会搭建私有仓库、发布到 Flathub,以及 GPG 签名和更新机制。
9.1 Flatpak 仓库基础
9.1.1 仓库概念
Flatpak 仓库基于 OSTree,一种类似 Git 的版本化文件系统存储格式。
| 概念 | 说明 |
|---|---|
| Remote (远程仓库) | 托管 Flatpak 包的 OSTree 仓库 |
| Collection | 仓库的逻辑分组 |
| Ref | 仓库中的对象引用(应用、运行时、扩展) |
| Commit | 仓库中的版本快照 |
| Branch | 分支(如 stable、beta) |
9.1.2 仓库类型
| 类型 | 说明 | 示例 |
|---|---|---|
| HTTP 仓库 | 通过 HTTP/HTTPS 访问 | Flathub |
| 本地仓库 | 本地文件系统路径 | 开发构建 |
| USB/离线 | 通过可移动介质分发 | 离线安装 |
9.1.3 管理远程仓库
# 列出所有远程仓库
flatpak remotes
# 详细信息
flatpak remote-show flathub
# 添加远程仓库
flatpak remote-add --if-not-exists myrepo https://flatpak.example.com/repo
# 添加用户级仓库
flatpak remote-add --user --if-not-exists myrepo https://flatpak.example.com/repo
# 修改仓库 URL
flatpak remote-modify myrepo --url=https://new-url.example.com/repo
# 禁用仓库
flatpak remote-modify myrepo --disable
# 启用仓库
flatpak remote-modify myrepo --enable
# 设置仓库优先级(数字越小优先级越高)
flatpak remote-modify myrepo --prio=1
# 删除仓库
flatpak remote-delete myrepo
# 导入 GPG 密钥
flatpak remote-modify myrepo --gpg-import=/path/to/key.gpg
# 设置代理
flatpak remote-modify myrepo --set-opt=http-proxy=http://proxy:8080
9.2 Flathub 发布流程
9.2.1 Flathub 概述
Flathub 是 Flatpak 最大的应用仓库,托管超过 2000 款应用。
Flathub 要求:
- 开源应用(GPL、MIT、Apache 等许可证)
- 应用必须可离线构建(不允许构建时联网)
- 应用必须通过审核流程
- 必须提供 AppStream 元数据
9.2.2 发布到 Flathub 的完整流程
# 步骤 1:Fork Flathub 仓库
# 访问 https://github.com/flathub/flathub
# 点击 "Fork" 按钮
# 步骤 2:克隆 Fork 的仓库
git clone https://github.com/YOUR_USERNAME/flathub.git
cd flathub
# 步骤 3:创建应用分支
git checkout -b com.example.MyApp
# 步骤 4:创建应用 Manifest
cat > com.example.MyApp.json << 'EOF'
{
"app-id": "com.example.MyApp",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "myapp",
"finish-args": [
"--share=ipc",
"--socket=wayland",
"--socket=fallback-x11",
"--share=network",
"--filesystem=xdg-download"
],
"modules": [
{
"name": "myapp",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://github.com/example/myapp.git",
"tag": "v1.0.0",
"commit": "abc123..."
}
]
}
]
}
EOF
# 步骤 5:本地测试构建
flatpak-builder --force-clean --repo=repo builddir com.example.MyApp.json
flatpak remote-add --no-gpg-verify local-repo repo
flatpak install local-repo com.example.MyApp
flatpak run com.example.MyApp
# 步骤 6:提交并推送
git add com.example.MyApp.json
git commit -m "Add com.example.MyApp"
git push origin com.example.MyApp
# 步骤 7:创建 Pull Request
# 在 GitHub 上创建 PR 到 flathub/flathub 的 master 分支
9.2.3 AppStream 元数据要求
应用必须提供 AppStream 元数据文件:
<!-- com.example.MyApp.metainfo.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>com.example.MyApp</id>
<name>My Application</name>
<summary>A short description</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<description>
<p>
A longer description of what the application does.
</p>
<p>Features include:</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
</ul>
</description>
<url type="homepage">https://example.com/myapp</url>
<url type="bugtracker">https://github.com/example/myapp/issues</url>
<developer id="com.example">
<name>Example Developer</name>
</developer>
<content_rating type="oars-1.1" />
<releases>
<release version="1.0.0" date="2026-05-01">
<description>
<p>Initial release.</p>
</description>
</release>
</releases>
<recommends>
<control>pointing</control>
<control>keyboard</control>
</recommends>
<requires>
<display_length compare="ge">360</display_length>
</requires>
</component>
9.2.4 桌面文件要求
# com.example.MyApp.desktop
[Desktop Entry]
Name=My Application
Comment=A short description
Exec=myapp %U
Icon=com.example.MyApp
Type=Application
Categories=Utility;Development;
StartupNotify=true
MimeType=text/plain;
9.2.5 Flathub 审核清单
| 检查项 | 要求 | 验证命令 |
|---|---|---|
| App ID | 反向域名格式 | flatpak info app-id |
| AppStream | 提供 .metainfo.xml | appstreamcli validate *.metainfo.xml |
| Desktop | 提供 .desktop 文件 | desktop-file-validate *.desktop |
| 图标 | 提供至少 128x128 图标 | 检查 share/icons/ |
| 离线构建 | 不依赖网络构建 | flatpak-builder --disable-download |
| 许可证 | 开源许可证 | 检查 project_license |
| 安全权限 | 最小权限原则 | 审查 finish-args |
# 验证 AppStream 元数据
appstreamcli validate com.example.MyApp.metainfo.xml
# 验证桌面文件
desktop-file-validate com.example.MyApp.desktop
# 离线构建测试
flatpak-builder --disable-download --force-clean --repo=repo builddir com.example.MyApp.json
9.3 搭建私有仓库
9.3.1 使用 OSTree 搭建
# 步骤 1:创建仓库目录
sudo mkdir -p /srv/flatpak-repo
sudo chown $(whoami) /srv/flatpak-repo
# 步骤 2:初始化 OSTree 仓库
ostree init --repo=/srv/flatpak-repo --mode=archive-z2
# 步骤 3:配置仓库(可选,设置 GPG 签名)
cat > /srv/flatpak-repo/config << 'EOF'
[core]
repo_version=1
mode=archive-z2
[remote "origin"]
url=https://example.com/flatpak-repo
gpg-verify=true
gpg-verify-summary=true
EOF
# 步骤 4:将应用导出到仓库
flatpak build-export /srv/flatpak-repo builddir stable
# 步骤 5:生成仓库摘要
flatpak build-update-repo /srv/flatpak-repo
# 步骤 6:通过 HTTP 提供仓库
# 使用 Nginx 或 Caddy 配置 HTTP 服务
9.3.2 使用 Nginx 提供 HTTP 仓库
# /etc/nginx/conf.d/flatpak-repo.conf
server {
listen 80;
server_name flatpak.example.com;
root /srv/flatpak-repo;
index index.html;
location / {
try_files $uri $uri/ =404;
autoindex on;
}
# 启用 Gzip 压缩
gzip on;
gzip_types application/octet-stream text/plain;
}
9.3.3 使用 Caddy 提供仓库
# Caddyfile
flatpak.example.com {
root * /srv/flatpak-repo
file_server
encode gzip
}
9.3.4 添加私有仓库
# 客户端添加仓库(无 GPG 签名)
flatpak remote-add --no-gpg-verify private-repo https://flatpak.example.com/repo/
# 客户端添加仓库(有 GPG 签名)
# 先获取 GPG 密钥
wget https://flatpak.example.com/repo/key.gpg
flatpak remote-add --gpg-import=key.gpg private-repo https://flatpak.example.com/repo/
# 从私有仓库安装应用
flatpak install private-repo com.example.MyApp
# 列出仓库中的应用
flatpak remote-ls private-repo
9.4 GPG 签名
9.4.1 生成 GPG 密钥
# 生成 GPG 密钥对
gpg --full-generate-key
# 选择选项:
# - 密钥类型: RSA and RSA
# - 密钥大小: 4096
# - 有效期: 0 (永不过期) 或设定有效期
# - 姓名: Flatpak Repository
# - 邮箱: flatpak@example.com
# 列出密钥
gpg --list-keys
# 导出公钥
gpg --output /srv/flatpak-repo/key.gpg --export flatpak@example.com
# 导出私钥(用于签名,妥善保管)
gpg --output /srv/flatpak-repo/key-private.gpg --export-secret-keys flatpak@example.com
9.4.2 签名仓库
# 配置仓库使用 GPG 签名
ostree --repo=/srv/flatpak-repo remote add origin \
--gpg-import=/srv/flatpak-repo/key.gpg \
--set=gpg-verify=true \
https://flatpak.example.com/repo
# 导出应用时自动签名
flatpak build-export --gpg-sign=flatpak@example.com \
--gpg-homedir=~/.gnupg \
/srv/flatpak-repo builddir stable
# 更新仓库摘要
flatpak build-update-repo --gpg-sign=flatpak@example.com \
--gpg-homedir=~/.gnupg \
/srv/flatpak-repo
9.4.3 客户端验证签名
# 客户端导入 GPG 公钥
wget https://flatpak.example.com/repo/key.gpg
flatpak remote-modify --gpg-import=key.gpg private-repo
# 验证签名
flatpak remote-info private-repo com.example.MyApp
# 如果签名验证失败,会报错:
# Error: GPG signature verification failed
9.5 仓库维护
9.5.1 更新仓库内容
# 导出新版本应用
flatpak build-export /srv/flatpak-repo builddir-new stable
# 更新仓库摘要
flatpak build-update-repo /srv/flatpak-repo
# 查看仓库中的应用列表
ostree --repo=/srv/flatpak-repo refs
# 查看应用的提交历史
ostree --repo=/srv/flatpak-repo log app/com.example.MyApp/x86_64/stable
9.5.2 清理旧版本
# 删除旧的提交(保留最近 3 个版本)
ostree --repo=/srv/flatpak-repo prune --refs-only --depth=3
# 删除特定应用的旧版本
ostree --repo=/srv/flatpak-repo prune --delete-commit=COMMIT_HASH
# 重新打包仓库(优化存储)
ostree --repo=/srv/flatpak-repo prune --refs-only
flatpak build-update-repo /srv/flatpak-repo
9.5.3 仓库统计
# 查看仓库大小
du -sh /srv/flatpak-repo/
# 查看对象数量
ostree --repo=/srv/flatpak-repo objects
# 查看应用数量
ostree --repo=/srv/flatpak-repo refs | grep "app/" | wc -l
9.6 镜像仓库
9.6.1 镜像 Flathub
# 创建 Flathub 镜像
ostree init --repo=/srv/flathub-mirror --mode=archive-z2
# 添加 Flathub 远程
ostree --repo=/srv/flathub-mirror remote add flathub \
https://dl.flathub.org/repo --gpg-import=/path/to/flathub-key.gpg
# 同步仓库
ostree --repo=/srv/flathub-mirror pull --mirror flathub
# 后续同步(增量更新)
ostree --repo=/srv/flathub-mirror pull --mirror flathub
# 客户端使用镜像
flatpak remote-modify flathub --url=https://mirror.example.com/flathub-mirror/
9.6.2 国内镜像配置
# 清华大学镜像
flatpak remote-modify flathub --url=https://mirrors.tuna.tsinghua.edu.cn/flathub
# 中科大镜像
flatpak remote-modify flathub --url=https://mirrors.ustc.edu.cn/flathub
# 华为云镜像
flatpak remote-modify flathub --url=https://mirrors.huaweicloud.com/flathub
# 验证镜像
flatpak remote-show flathub
9.7 Delta 更新与优化
9.7.1 Delta 更新机制
OSTree 支持增量更新 (Delta Update),只传输变化的部分:
# 生成 Delta(在仓库服务端)
flatpak build-update-repo --generate-static-deltas /srv/flatpak-repo
# 查看 Delta 大小
ls -lh /srv/flatpak-repo/deltas/
# 客户端更新时会自动使用 Delta
flatpak update com.example.MyApp
9.7.2 网络优化
# 启用 HTTP/2(提升并发下载性能)
# 在 Nginx 配置中
server {
listen 443 ssl http2;
# ...
}
# 启用 Brotli 压缩
# 在 Nginx 配置中
brotli on;
brotli_types application/octet-stream;
9.8 业务场景
场景 1:企业应用商店
#!/bin/bash
# setup-enterprise-repo.sh
# 搭建企业内部 Flatpak 应用商店
REPO_DIR="/srv/enterprise-flatpak"
GPG_EMAIL="admin@enterprise.com"
# 初始化仓库
mkdir -p "$REPO_DIR"
ostree init --repo="$REPO_DIR" --mode=archive-z2
# 生成 GPG 密钥(如果没有)
if ! gpg --list-keys "$GPG_EMAIL" &>/dev/null; then
cat > /tmp/gpg-key-config << EOF
%echo Generating GPG key for Flatpak repository
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Enterprise Flatpak
Name-Email: $GPG_EMAIL
Expire-Date: 0
%commit
%echo Done
EOF
gpg --batch --gen-key /tmp/gpg-key-config
fi
# 导出公钥
gpg --output "$REPO_DIR/key.gpg" --export "$GPG_EMAIL"
echo "=== 企业 Flatpak 仓库初始化完成 ==="
echo "仓库路径: $REPO_DIR"
echo "GPG 邮箱: $GPG_EMAIL"
echo "公钥文件: $REPO_DIR/key.gpg"
echo ""
echo "添加应用步骤:"
echo " 1. flatpak build-export $REPO_DIR builddir stable"
echo " 2. flatpak build-update-repo $REPO_DIR"
echo " 3. 客户端: flatpak remote-add --gpg-import=key.gpg enterprise https://flatpak.enterprise.com/repo/"
场景 2:多环境管理
#!/bin/bash
# manage-envs.sh - 管理开发/测试/生产环境的 Flatpak 仓库
ENV=$1 # dev, staging, prod
case $ENV in
dev)
REPO_URL="https://flatpak-dev.internal.com/repo"
;;
staging)
REPO_URL="https://flatpak-staging.internal.com/repo"
;;
prod)
REPO_URL="https://flatpak.internal.com/repo"
;;
*)
echo "用法: $0 {dev|staging|prod}"
exit 1
;;
esac
# 切换仓库 URL
flatpak remote-modify internal-repo --url="$REPO_URL"
# 更新应用
flatpak update
echo "已切换到 $ENV 环境: $REPO_URL"
9.9 注意事项
⚠️ Flathub 审核周期
新应用首次提交到 Flathub 可能需要数天到数周的审核时间。请耐心等待审核反馈。
⚠️ GPG 密钥安全
私钥必须妥善保管。如果私钥泄露,攻击者可以向仓库注入恶意应用。建议使用硬件安全模块 (HSM) 或离线签名服务器。
⚠️ 仓库备份
定期备份仓库数据。OSTree 仓库的数据丢失将导致所有已安装应用无法更新。
⚠️ HTTPS 必需
生产环境必须使用 HTTPS。HTTP 仓库容易被中间人攻击。