第 5 章:Manifest 文件详解
第 5 章:Manifest 文件详解
本章目标:全面理解 Flatpak Manifest 的结构与语法,学会编写完整的应用构建配置。
5.1 Manifest 概述
Manifest(清单文件)是 Flatpak 构建过程的核心配置。它描述了:
- 应用的基本信息(ID、名称、版本)
- 使用的运行时和 SDK
- 所需的权限
- 构建模块(源代码获取、编译步骤)
- 扩展点(可选组件)
支持的格式
| 格式 | 文件扩展名 | 推荐程度 | 说明 |
|---|---|---|---|
| JSON | .json | ⭐⭐⭐ 最推荐 | flatpak-builder 原生支持 |
| YAML | .yaml / .yml | ⭐⭐ 推荐 | 更易读,需 JSON 转换 |
| JSON5 | .json5 | ⭐ 支持 | 支持注释和尾逗号 |
# YAML → JSON 转换工具
pip install pyyaml
python -c "
import yaml, json, sys
with open(sys.argv[1]) as f:
data = yaml.safe_load(f)
print(json.dumps(data, indent=4))
" app.yaml > app.json
5.2 Manifest 基本结构
5.2.1 最小化 Manifest
{
"app-id": "com.example.HelloWorld",
"runtime": "org.freedesktop.Platform",
"runtime-version": "24.08",
"sdk": "org.freedesktop.Sdk",
"command": "hello-world",
"modules": [
{
"name": "hello-world",
"buildsystem": "simple",
"build-commands": [
"gcc -o hello-world hello.c -I/usr/include",
"install -Dm755 hello-world /app/bin/hello-world"
],
"sources": [
{
"type": "file",
"url": "https://example.com/hello.c",
"sha256": "abc123..."
}
]
}
]
}
5.2.2 完整 Manifest 结构
{
"app-id": "com.example.MyApp",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"sdk-extensions": ["org.freedesktop.Sdk.Extension.rust-stable"],
"command": "myapp",
"separate-locales": true,
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--socket=pulseaudio",
"--device=dri",
"--talk-name=org.freedesktop.Notifications",
"--filesystem=xdg-download"
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin",
"env": {
"CARGO_HOME": "/run/build/myapp/cargo"
},
"build-args": ["--share=network"]
},
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/man"
],
"modules": [
{
"name": "dependency-a",
"buildsystem": "cmake-ninja",
"sources": [
{
"type": "archive",
"url": "https://example.com/dep-a-1.0.tar.gz",
"sha256": "def456..."
}
]
},
{
"name": "myapp",
"buildsystem": "meson",
"config-opts": ["-Dbuildtype=release"],
"sources": [
{
"type": "git",
"url": "https://github.com/example/myapp.git",
"tag": "v1.0.0",
"commit": "abc123..."
}
],
"post-install": [
"install -Dm644 icons/hicolor/256x256/apps/com.example.MyApp.png /app/share/icons/hicolor/256x256/apps/com.example.MyApp.png",
"install -Dm644 data/com.example.MyApp.desktop /app/share/applications/com.example.MyApp.desktop",
"install -Dm644 data/com.example.MyApp.metainfo.xml /app/share/metainfo/com.example.MyApp.metainfo.xml"
]
}
],
"cleanup-commands": ["rm -rf /app/share/gtk-doc"],
"rename-icon": "myapp",
"rename-desktop-file": "myapp.desktop",
"rename-appdata-file": "myapp.metainfo.xml"
}
5.3 顶层字段详解
5.3.1 应用标识
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
app-id | string | ✅ | 应用唯一标识,遵循反向域名格式 |
id | string | ❌ | app-id 的别名 |
branch | string | ❌ | 默认 stable |
应用 ID 规范:
# 推荐格式
com.company.AppName # 商业应用
org.organization.AppName # 组织/开源项目
io.github.username.AppName # GitHub 托管项目
net.project.AppName # 网络项目
# 反面示例(不推荐)
myapp # 太简短
com.example.app123 # 包含数字后缀
5.3.2 运行时配置
| 字段 | 类型 | 说明 |
|---|---|---|
runtime | string | 运行时 ID |
runtime-version | string | 运行时版本 |
sdk | string | SDK ID |
sdk-extensions | string[] | SDK 扩展列表 |
base | string | 基础应用(用于应用扩展) |
base-version | string | 基础应用版本 |
inherit-extensions | bool | 是否继承基础应用的扩展 |
5.3.3 应用元数据
| 字段 | 类型 | 说明 |
|---|---|---|
command | string | 启动命令 |
separate-locales | bool | 分离语言包(默认 true) |
tags | string[] | 应用标签 |
default-branch | string | 默认分支名 |
collection-id | string | OSTree 集合 ID |
5.4 权限声明 (finish-args)
finish-args 是一个字符串数组,每个元素是一个 Flatpak 权限参数:
{
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--socket=fallback-x11",
"--socket=pulseaudio",
"--socket=ssh-auth",
"--device=dri",
"--device=shm",
"--filesystem=home",
"--filesystem=xdg-download",
"--filesystem=~/Projects:create",
"--filesystem=ro:~/.config",
"--env=GTK_THEME=Adwaita:dark",
"--talk-name=org.freedesktop.Notifications",
"--talk-name=org.kde.StatusNotifierWatcher",
"--system-talk-name=org.freedesktop.login1",
"--own-name=com.example.MyApp",
"--no-talk-name=*"
]
}
常见应用类型权限模板
文本编辑器
{
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--filesystem=home",
"--talk-name=org.freedesktop.Notifications",
"--talk-name=org.freedesktop.FileManager1"
]
}
网络浏览器
{
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--socket=pulseaudio",
"--device=dri",
"--device=all",
"--filesystem=home",
"--filesystem=host",
"--talk-name=org.freedesktop.Notifications",
"--system-talk-name=org.freedesktop.login1"
]
}
媒体播放器
{
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--socket=pulseaudio",
"--device=dri",
"--filesystem=home",
"--talk-name=org.freedesktop.Notifications"
]
}
5.5 构建选项 (build-options)
5.5.1 环境变量
{
"build-options": {
"env": {
"CFLAGS": "-O2 -g",
"CXXFLAGS": "-O2 -g",
"LDFLAGS": "-Wl,--as-needed",
"PYTHON": "/usr/bin/python3",
"CARGO_HOME": "/run/build/myapp/cargo"
}
}
}
5.5.2 路径配置
{
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm18/bin",
"prepend-path": "/app/bin",
"append-ld-library-path": "/app/lib",
"append-pkg-config-path": "/app/lib/pkgconfig"
}
}
5.5.3 构建参数
{
"build-options": {
"build-args": ["--share=network", "--filesystem=host"],
"test-args": ["--no-net"],
"config-opts": ["-Dprefix=/app", "-Dbuildtype=release"],
"cflags": "-O2",
"cxxflags": "-O2",
"ldflags": "-Wl,--as-needed"
}
}
5.5.4 架构相关配置
{
"build-options": {
"arch": {
"x86_64": {
"env": {
"CFLAGS": "-march=x86-64-v2"
}
},
"aarch64": {
"env": {
"CFLAGS": "-march=armv8-a"
}
}
}
}
}
5.6 模块 (Modules)
5.6.1 模块类型
| 构建系统 | buildsystem 值 | 适用项目 |
|---|---|---|
| Meson | meson | GNOME 生态、现代 C/C++ 项目 |
| CMake + Ninja | cmake-ninja | CMake 项目 |
| CMake + Make | cmake | CMake 项目(回退) |
| Autotools | autotools | 传统 GNU 项目 |
| QMake | qmake | Qt 项目 |
| 简单脚本 | simple | 自定义构建命令 |
| Python | python | Python 包 |
| Perl | perl | Perl 模块 |
5.6.2 源类型
| 源类型 | 说明 | 关键字段 |
|---|---|---|
archive | tar.gz/zip 等压缩包 | url, sha256 |
git | Git 仓库 | url, tag/commit/branch |
file | 单个文件 | url, sha256, dest-filename |
dir | 本地目录 | path |
patch | 补丁文件 | path 或 url |
shell | Shell 命令 | commands |
extra-data | 额外数据(运行时下载) | url, sha256, size |
5.6.3 完整模块示例
{
"name": "myapp",
"buildsystem": "meson",
"config-opts": [
"-Dbuildtype=release",
"-Dtests=false",
"-Ddocs=false"
],
"builddir": true,
"sources": [
{
"type": "git",
"url": "https://github.com/example/myapp.git",
"tag": "v1.0.0",
"commit": "abc123def456789..."
},
{
"type": "patch",
"path": "patches/fix-build.patch"
},
{
"type": "shell",
"commands": [
"sed -i 's|/usr/local|/app|g' meson.build"
]
}
],
"post-install": [
"install -Dm644 ../data/com.example.MyApp.desktop /app/share/applications/com.example.MyApp.desktop",
"install -Dm644 ../data/com.example.MyApp.metainfo.xml /app/share/metainfo/com.example.MyApp.metainfo.xml",
"glib-compile-schemas /app/share/glib-2.0/schemas/"
],
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/man"
]
}
5.6.4 Python 模块示例
{
"name": "python-requests",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} requests"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/.../requests-2.31.0-py3-none-any.whl",
"sha256": "abc123..."
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/.../urllib3-2.0.7-py3-none-any.whl",
"sha256": "def456..."
}
]
}
5.6.5 Rust 模块示例
{
"name": "myapp",
"buildsystem": "simple",
"build-commands": [
"cargo --offline fetch --manifest-path Cargo.toml",
"cargo --offline build --release",
"install -Dm755 target/release/myapp /app/bin/myapp"
],
"sources": [
{
"type": "git",
"url": "https://github.com/example/myapp.git",
"tag": "v1.0.0",
"commit": "abc123..."
},
{
"type": "shell",
"commands": [
"mkdir -p .cargo",
"cat > .cargo/config.toml << 'TOML'",
"[net]",
"offline = true",
"[source.crates-io]",
"replace-with = \"vendored-sources\"",
"[source.vendored-sources]",
"directory = \"vendor\"",
"TOML"
]
},
"cargo-sources.json"
]
}
5.7 清理规则 (cleanup)
{
"cleanup": [
"/include",
"/lib/pkgconfig",
"/lib/cmake",
"/share/man",
"/share/doc",
"/share/gtk-doc",
"*.a",
"*.la"
],
"cleanup-commands": [
"rm -rf /app/share/icons/hicolor/256x256",
"find /app -name '*.pyc' -delete"
],
"cleanup-platform": [
"/lib/debug"
]
}
5.8 文件重命名
{
"rename-desktop-file": "org.example.myapp.desktop",
"rename-appdata-file": "org.example.myapp.metainfo.xml",
"rename-icon": "myapp-icon"
}
这些选项将自动重命名文件为与 app-id 匹配的名称。
5.9 完整 Manifest 示例
示例 1:简单的 GTK 应用
{
"app-id": "com.example.TextEditor",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "text-editor",
"finish-args": [
"--share=ipc",
"--socket=wayland",
"--socket=fallback-x11",
"--filesystem=home",
"--talk-name=org.freedesktop.Notifications"
],
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/man"
],
"modules": [
{
"name": "text-editor",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://github.com/example/text-editor.git",
"tag": "1.0.0",
"commit": "abc123..."
}
]
}
]
}
示例 2:Electron 应用
{
"app-id": "com.example.ElectronApp",
"runtime": "org.freedesktop.Platform",
"runtime-version": "24.08",
"sdk": "org.freedesktop.Sdk",
"base": "org.electronjs.Electron2.BaseApp",
"base-version": "24.08",
"command": "electron-app",
"separate-locales": false,
"finish-args": [
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--socket=pulseaudio",
"--share=network",
"--device=dri",
"--filesystem=home",
"--talk-name=org.freedesktop.Notifications"
],
"modules": [
{
"name": "electron-app",
"buildsystem": "simple",
"build-commands": [
"cp -r app /app/electron-app",
"install -Dm755 run.sh /app/bin/electron-app",
"install -Dm644 com.example.ElectronApp.desktop /app/share/applications/com.example.ElectronApp.desktop",
"install -Dm644 icon.png /app/share/icons/hicolor/512x512/apps/com.example.ElectronApp.png"
],
"sources": [
{
"type": "archive",
"url": "https://github.com/example/electron-app/releases/download/v1.0.0/electron-app-linux-x64.zip",
"sha256": "abc123..."
}
]
}
]
}
5.10 业务场景
场景:从零编写 Manifest
假设要打包一个名为 “MyPainter” 的 GTK4 绘图应用:
# 1. 创建项目目录
mkdir -p mypainter-flatpak
cd mypainter-flatpak
# 2. 创建 Manifest
cat > com.example.MyPainter.json << 'JSONEOF'
{
"app-id": "com.example.MyPainter",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "mypainter",
"finish-args": [
"--share=ipc",
"--socket=wayland",
"--socket=fallback-x11",
"--filesystem=xdg-pictures",
"--talk-name=org.freedesktop.Notifications"
],
"modules": [
{
"name": "mypainter",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://github.com/example/mypainter.git",
"tag": "v1.0.0"
}
]
}
]
}
JSONEOF
# 3. 验证 JSON 语法
python3 -m json.tool com.example.MyPainter.json > /dev/null && echo "JSON 语法正确"
5.11 注意事项
⚠️ SHA256 校验和
所有远程源都必须提供sha256校验和。省略校验和会导致构建失败(安全策略)。
⚠️ app-id 不可更改
应用 ID 一旦确定并发布,不可更改。更改 ID 等于发布全新应用,会丢失用户数据。
⚠️ 模块顺序
模块按照数组顺序依次构建。如果模块 B 依赖模块 A,A 必须排在 B 前面。
⚠️ 离线构建
Flathub 要求所有构建都是离线的(不允许构建时联网下载依赖)。所有依赖必须在sources中预先声明。