强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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.xmlappstreamcli 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 仓库容易被中间人攻击。


9.10 扩展阅读