flutpak 0.4.0-beta.3
flutpak: ^0.4.0-beta.3 copied to clipboard
CLI tool that generates Flatpak manifests and offline source bundles for Flutter applications. One command prepares everything needed for a Flathub-compatible offline build: generated-sources.json, ma [...]
flutpak #
A Dart CLI tool that automates Flatpak packaging for Flutter applications.
Describe your config once in pubspec.yaml, run flutpak init once to
scaffold your template manifest, then run flutpak generate on every CI
build to produce a fully-substituted, flatpak-builder-ready output.
Highlights #
init+generatesplit — one-time scaffold vs. every-build generation; the editable template is committed to git, the substituted output is gitignored- No Python — pure Dart, compiles to a single native binary for CI
- Config in
pubspec.yaml— same pattern asmsix_config,flutter_native_splash - Placeholder substitution —
__FLATPAK_TAG__and__FLATPAK_COMMIT__are resolved bygenerateat build time, never baked into the template - Patches registry — known packages (e.g.
objectbox_flutter_libs) get their patches resolved and injected into the generated manifest automatically atgeneratetime - Validation on every run —
generateerrors early if the template is missing placeholders or its fields diverge from config - Retry on transient errors — pub.dev and Flutter artifact downloads retry on 429/5xx
Table of Contents #
- flutpak
Prerequisites #
| Tool | When needed | Notes |
|---|---|---|
| Linux | Always | flutpak targets Linux Flatpak packaging only |
| git | Always | Version detection and commit-hash resolution |
| Internet access | init, generate, sources, flutter |
Downloads from pub.dev and storage.googleapis.com |
| Flutter SDK | Flutter projects | Path via $FLUTTER_ROOT or --sdk; pure-Dart projects can omit this |
| Dart SDK ≥ 3.0 | Building from source only | Not required when using a pre-built binary |
flatpak-builder |
Local Flatpak builds | Only needed when actually building the Flatpak, not during flutpak generate |
org.freedesktop.Sdk |
Local Flatpak builds | Install via flatpak install flathub org.freedesktop.Sdk//25.08 |
Installation #
Pre-built binary (recommended) #
Download the binary for your platform from the
releases page and place it
somewhere on your $PATH:
sudo mv flutpak /usr/local/bin/
Via setup-flutpak action (CI) #
The repository ships a composite action that compiles and installs flutpak
automatically. See CI/CD integration for full usage.
- uses: o-murphy/flutpak/.github/actions/setup-flutpak@main
From source #
Using make:
git clone https://github.com/o-murphy/flutpak.git
cd flutpak
make build # regenerates version.dart + compiles binary
sudo mv flutpak /usr/local/bin/
Without make:
dart run tool/update_version.dart
dart compile exe bin/flutpak.dart -o flutpak
Step-by-step setup #
Step 1 — Add config to pubspec.yaml #
Add a flutpak: section to your app's pubspec.yaml (or create a standalone
flutpak.yaml — but not both).
Minimum viable config — only app_id and finish_args are truly required:
flutpak:
manifest:
app_id: io.github.YourOrg.YourApp
finish_args:
- --share=ipc
- --socket=wayland
- --device=dri
Everything else is either optional or auto-detected at runtime. For Flutter projects, add the SDK path:
flutpak:
flutter:
sdk: $FLUTTER_ROOT # or absolute path; omit for pure-Dart projects
manifest:
app_id: io.github.YourOrg.YourApp
finish_args:
- --share=ipc
- --socket=wayland
- --device=dri
See Full config reference for all options.
Step 2 — Create required asset files #
flutpak init validates that these files exist before generating anything.
Create and commit them first:
<your-project>/
├── pubspec.yaml
├── pubspec.lock
└── app/
└── share/
├── metainfo/
│ └── <app_id>.metainfo.xml
├── applications/
│ └── <app_id>.desktop
└── icons/
└── hicolor/
└── 256x256/
└── apps/
└── <app_id>.png # minimum 256x256 required by Flathub
Minimal <app_id>.desktop:
[Desktop Entry]
Name=Your App
Exec=yourapp
Icon=io.github.YourOrg.YourApp
Type=Application
Categories=Utility;
Minimal <app_id>.metainfo.xml:
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.YourOrg.YourApp</id>
<metadata_license>MIT</metadata_license>
<project_license>MIT</project_license>
<name>Your App</name>
<summary>Short one-line description</summary>
<releases>
<release version="0.1.0" date="2025-01-01"/>
</releases>
</component>
For full requirements on these files, see the Flathub app-author documentation.
Step 3 — First run #
flutpak init
This is a one-time command. It generates the following files and then
immediately runs generate to populate flatpak/generated/:
flatpak/
├── <app_id>.yml # editable template manifest — commit this
├── <name>-wrapper.sh # Flutter launcher wrapper — commit this
├── flathub.json # Flathub submission config — commit this
├── .gitignore # contains: generated/
└── generated/ # gitignored, ready for flatpak-builder
├── <app_id>.yml
├── flathub.json
├── generated-sources.json
└── patches/
Commit flatpak/<app_id>.yml, flatpak/<name>-wrapper.sh,
flatpak/flathub.json, and flatpak/.gitignore. Do not commit
flatpak/generated/ — it is gitignored by design.
flutpak init errors if the template already exists. Use --force to
overwrite an existing scaffold.
Step 4 — Review and customize the template #
Open flatpak/<app_id>.yml and adjust build-commands, sdk-extensions,
finish-args, and any other fields for your project. The template is yours —
flutpak never overwrites it on subsequent runs.
The generated template already contains inline guidance comments that explain which sections are safe to edit. Key rules:
| Section | Guidance |
|---|---|
finish-args: |
Safe to edit — add/remove sandbox permissions |
build-commands: |
Safe to edit — add steps, adjust install paths |
build-options: |
Safe to edit — add env vars, path overrides |
sdk-extensions: |
Safe to edit |
modules: |
Safe to edit — add extra modules |
sources: — extra archives |
Safe to add/remove |
__FLATPAK_TAG__ / __FLATPAK_COMMIT__ |
Do not remove — required by generate |
Patch sources (type: patch) |
Do not add manually — injected automatically by generate from your patches: config; adding them to the template causes duplicates |
Step 5 — Build locally #
Point flatpak-builder at the generated manifest:
flatpak-builder --repo=repo --force-clean build-dir \
flatpak/generated/<app_id>.yml
See Validating and building locally for the full lint and validation workflow.
Step 6 — CI: generate on each release #
On every release build, run generate with the release tag:
flutpak generate --tag ${{ github.ref_name }}
This reads the committed template, resolves the tag and commit SHA, generates
generated-sources.json, substitutes __FLATPAK_TAG__ and
__FLATPAK_COMMIT__, and writes everything to flatpak/generated/.
See CI/CD integration for a complete GitHub Actions workflow.
Step 7 — Submit to Flathub #
Open a PR to your app's Flathub repository. Copy the contents of
flatpak/generated/ into the repo root:
<flathub-repo>/
├── <app_id>.yml # flatpak/generated/<app_id>.yml
├── generated-sources.json # flatpak/generated/generated-sources.json
├── flathub.json # flatpak/generated/flathub.json
└── patches/ # flatpak/generated/patches/ (if any)
For complete submission requirements see the Flathub app-author documentation.
Full config reference #
Config lives in one of two places (error if both exist):
| Location | Key |
|---|---|
pubspec.yaml |
flutpak: section |
flutpak.yaml |
standalone file |
Complete YAML with all options #
# pubspec.yaml — flutpak: section (or standalone flutpak.yaml)
flutpak:
output: flatpak # default
pub:
locks:
- pubspec.lock
- $FLUTTER_ROOT/packages/flutter_tools/pubspec.lock # optional
flutter:
sdk: /home/user/flutter # or set $FLUTTER_ROOT; omit for pure-Dart
patch: flatpak/patches/flutter/shared.sh.patch # optional
patches: # optional project-level patches
- package: objectbox_flutter_libs
path: flatpak/patches/objectbox.patch
dest_subpath: linux
manifest:
app_id: io.github.YourOrg.YourApp # required
runtime_version: '25.08' # default: '25.08'
finish_args: # required
- --share=ipc
- --socket=wayland
- --device=dri
sdk_extensions:
- org.freedesktop.Sdk.Extension.llvm20
# Auto-detected if omitted (info printed on init):
command: yourapp # default: last segment of app_id
repo_url: https://github.com/... # default: git remote get-url origin
# Asset source paths (relative to project root):
metainfo_path: app/share/metainfo/<app_id>.metainfo.xml # default
desktop_entry_path: app/share/applications/<app_id>.desktop # default
icons: # default: single 256x256 entry
- size: 256x256 # required when icons: key is present
path: app/share/icons/hicolor/256x256/apps/<app_id>.png
# optional additional sizes:
- size: 512x512
path: app/share/icons/hicolor/512x512/apps/<app_id>.png
- size: scalable
path: app/share/icons/hicolor/scalable/apps/<app_id>.svg
# Other optional fields:
extra_modules:
- flatpak/modules/bclibc.yml
extra_sources: []
env: {}
build_options:
append_path: /custom/bin
prepend_ld_library_path: /custom/lib
env:
MY_VAR: value
flutter_version_file: flatpak/flutter.version # default when flutter configured
Field reference table #
| Field | Type | Default | Notes |
|---|---|---|---|
output |
string | flatpak |
Output directory for generated files |
pub.locks |
list | [pubspec.lock] |
Lock files to scan; $ENV vars expanded |
flutter.sdk |
string | $FLUTTER_ROOT |
Flutter SDK path; omit for pure-Dart |
flutter.patch |
string | — | Custom patch for setup-flutter.sh |
flutter_version_file |
string | <output>/flutter.version |
Written when Flutter is configured |
patches |
list | [] |
Project-level package patches |
manifest.app_id |
string | required | Reverse-DNS app ID |
manifest.runtime_version |
string | 25.08 |
Freedesktop runtime version |
manifest.command |
string | last segment of app_id |
Executable name inside /app/bin/ |
manifest.repo_url |
string | git remote get-url origin |
Source git URL written into template |
manifest.finish_args |
list | required | Flatpak sandbox permissions |
manifest.sdk_extensions |
list | [] |
e.g. llvm20, rust |
manifest.metainfo_path |
string | app/share/metainfo/<id>.metainfo.xml |
Validated on init and generate |
manifest.desktop_entry_path |
string | app/share/applications/<id>.desktop |
Validated on init and generate |
manifest.icons |
list | [{size: 256x256, path: app/share/icons/…}] |
Must include 256x256 if key is present |
manifest.extra_modules |
list | [] |
YAML files included verbatim in modules |
manifest.extra_sources |
list | [] |
Verbatim flatpak source entries |
manifest.env |
map | {} |
Build-time env vars (shorthand) |
manifest.build_options.append_path |
string | — | Appended to PATH during build |
manifest.build_options.prepend_ld_library_path |
string | — | Prepended to LD_LIBRARY_PATH |
manifest.build_options.env |
map | {} |
Merged with top-level env: |
Commands reference #
init #
flutpak init [--config <path>] [--sdk <path>] [--force]
One-time setup. Generates the editable template manifest, wrapper script,
flathub.json, and flatpak/.gitignore, then immediately runs generate.
- Errors if the template (
flatpak/<app_id>.yml) already exists — use--forceto overwrite. - Validates that all asset files (metainfo, desktop entry, icons) exist.
- Auto-detects
repo_urlfromgit remote get-url origin.
| Flag | Description |
|---|---|
--config |
Path to config file (default: auto-detected pubspec.yaml or flutpak.yaml) |
--sdk |
Flutter SDK path; overrides flutter.sdk: in config and $FLUTTER_ROOT |
--force |
Overwrite existing template and wrapper |
generate #
flutpak generate [--tag v1.2.3] [--commit sha] [--config <path>] [--sdk <path>]
[--no-sources] [--pub-only] [--flutter-only] [--dry-run]
Every-build command. Reads the committed template, validates it against
config, generates generated-sources.json, substitutes __FLATPAK_TAG__ and
__FLATPAK_COMMIT__, and writes everything to flatpak/generated/.
- Errors if the template does not exist (run
flutpak initfirst). - Errors if
__FLATPAK_TAG__or__FLATPAK_COMMIT__are missing from the template. - Errors if
app-id,command, orruntime-versionin the template differ from config. - Errors if any asset file (metainfo, desktop entry, icon) does not exist.
| Flag | Description |
|---|---|
--tag |
Git tag embedded in the manifest (e.g. v1.2.3) |
--commit |
Full git commit SHA; defaults to git rev-parse HEAD |
--config |
Path to config file |
--sdk |
Flutter SDK path |
--no-sources |
Skip source generation; copy template only |
--pub-only |
Generate only pub package sources |
--flutter-only |
Generate only Flutter SDK sources |
--dry-run |
Print what would be written without writing any files |
pub #
flutpak pub [--lock <path>] [--output <dir>]
Generate pub package sources only. Reads pubspec.lock (and any additional
lock files specified via --lock) and writes generated-sources.json.
flutter #
flutpak flutter [--sdk <path>] [--output <dir>]
Generate Flutter SDK sources only. Reads engine version from the SDK and
writes artifact entries to generated-sources.json.
sources #
flutpak sources [--lock <path>] [--sdk <path>] [--output <dir>]
Generate all sources (pub + Flutter SDK) combined into a single
generated-sources.json.
Note
pub, flutter, and sources are for advanced / standalone use.
They are intended for users who write their Flatpak manifest by hand and need
only the source list as a JSON file to embed themselves. In the standard
init + generate workflow you never need to call them directly — generate
handles source generation internally and injects patch sources into the
generated manifest automatically.
sdk-ext #
flutpak sdk-ext [--sdk <path>] [--output <dir>]
Generate a Flutter SDK Extension manifest for Flathub
(org.freedesktop.Sdk.Extension.flutter3) to share the Flutter SDK across
multiple apps on the same machine.
--tag / --commit behavior #
--tag |
--commit |
Tag in manifest | Commit in manifest |
|---|---|---|---|
v1.2.3 |
— | v1.2.3 |
Resolved via git rev-parse v1.2.3^{} |
| — | abc123 |
abc123 |
abc123 |
| — | — | HEAD SHA | HEAD SHA |
v1.2.3 |
abc123 |
v1.2.3 |
abc123 (explicit override) |
When neither flag is passed, the current HEAD SHA is used for both values so
flatpak-builder can fetch and build the revision without a real release tag.
For release builds, always pass --tag. --tag requires the tag to exist
locally — use fetch-depth: 0 in your checkout step so the tag is available.
Manifest lifecycle #
The architecture separates the editable template (committed to git) from the generated output (gitignored):
flatpak/
├── <app_id>.yml <- editable template — committed to git
│ contains __FLATPAK_TAG__ and __FLATPAK_COMMIT__
├── <name>-wrapper.sh <- committed to git
├── flathub.json <- committed to git
├── patches/ <- patch files — committed to git
├── .gitignore <- contains: generated/
└── generated/ <- gitignored, never commit this
├── <app_id>.yml <- final manifest (placeholders substituted)
├── flathub.json <- copy
├── generated-sources.json
└── patches/ <- copy
Phase 1 — flutpak init (run once)
Creates flatpak/<app_id>.yml with __FLATPAK_TAG__ and __FLATPAK_COMMIT__
in the app git source block. Commit this file — it is the starting point that
reviewers inspect and that generate reads on every subsequent build.
Phase 2 — flutpak generate --tag vX.Y.Z (run on every CI build)
Reads the committed template, resolves the tag and commit SHA, generates
generated-sources.json, substitutes the placeholders, and copies everything
to flatpak/generated/. The template is never modified. flatpak-builder
consumes flatpak/generated/<app_id>.yml.
CI/CD integration #
setup-flutpak action #
- uses: o-murphy/flutpak/.github/actions/setup-flutpak@main
# Builds from the same ref as the 'uses:' directive by default.
# Pin to a specific release:
# with:
# version: v0.4.0-beta.1
| Input | Description | Default |
|---|---|---|
version |
Release tag, commit SHA, or branch to compile | ref pinned in uses: directive |
install_dir |
Directory where the flutpak binary is placed |
/usr/local/bin |
The repository also ships a flutter composite action with
runner.arch-aware cache keys — it works correctly on both ubuntu-latest
(x86_64) and ubuntu-24.04-arm (aarch64) runners:
- uses: o-murphy/flutpak/.github/actions/flutter@main
with:
flutter-version: stable # or read from flatpak/flutter.version
cache: true
| Input | Description | Default |
|---|---|---|
flutter-version |
Version tag (e.g. 3.41.6), stable, or beta |
stable |
cache |
Cache the SDK between runs | true |
| Output | Description |
|---|---|
flutter-path |
Absolute path to the installed Flutter SDK |
The action also exports FLUTTER_ROOT and FLUTTER_HOME env vars and adds
flutter/bin to $PATH, so flutpak generate picks up the SDK automatically
without an explicit --sdk flag.
generate action #
Runs flutpak generate, validates metainfo, and uploads the generated manifest
and sources as a workflow artifact. Requires Flutter to be installed beforehand
(e.g. via the flutter action above).
- uses: o-murphy/flutpak/.github/actions/generate@main
with:
tag: ${{ inputs.tag }} # or pass 'commit:' for non-tag builds
# commit: ${{ github.sha }} # used when 'tag' is empty
metainfo-path: app/share/metainfo/<app_id>.metainfo.xml
artifact-name: flatpak-generated
| Input | Description | Default |
|---|---|---|
tag |
Git tag to embed in the manifest (mutually exclusive with commit) |
— |
commit |
Commit SHA; defaults to github.sha when empty |
— |
sdk |
Flutter SDK path; auto-detected from FLUTTER_ROOT or flutter in PATH |
— |
metainfo-path |
Path to .metainfo.xml; appstream is installed automatically if needed |
— |
artifact-name |
Upload generated files under this artifact name | flutpak-artifacts |
retention-days |
Artifact retention in days | 2 |
flutpak-version |
flutpak version to install; defaults to the same ref as the uses: directive |
— |
build-flatpak action #
Installs org.flatpak.Builder, lints the manifest, builds via flathub-build,
lints the repo, exports a .flatpak bundle, and optionally uploads it.
- uses: o-murphy/flutpak/.github/actions/build-flatpak@main
id: build
with:
manifest: flatpak/generated/<app_id>.yml
app-id: io.github.YourOrg.YourApp
artifact-name: myapp-flatpak
github-token: ${{ secrets.GITHUB_TOKEN }} # for private source downloads
# Downstream steps can reference:
# ${{ steps.build.outputs.bundle }} — path to the .flatpak file
# ${{ steps.build.outputs.arch }} — x86_64 or aarch64
# ${{ steps.build.outputs.artifact-url }} — download URL of the uploaded artifact
| Input | Description | Default |
|---|---|---|
manifest |
Path to the generated Flatpak manifest | required |
app-id |
Flatpak application ID | required |
arch |
Target architecture (x86_64 or aarch64); auto-detected from flatpak --default-arch |
— |
bundle |
Output .flatpak filename |
<app-id>_<arch>.flatpak |
artifact-name |
Upload bundle under this artifact name; skip upload if empty | — |
retention-days |
Artifact retention in days | 2 |
github-token |
GitHub token written to ~/.netrc for private source downloads |
— |
| Output | Description |
|---|---|
bundle |
Path to the exported .flatpak bundle |
arch |
Architecture used for the build |
artifact-url |
Download URL of the uploaded artifact (empty if artifact-name is unset) |
Release workflow example #
The generate and build-flatpak actions let you split generation (runs once)
from building (can fan out across multiple architectures):
name: Flatpak release
on:
push:
tags: ['v*']
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required for --tag to resolve the commit
- uses: o-murphy/flutpak/.github/actions/flutter@main
id: flutter
with:
flutter-version: stable
cache: true
- run: flutter pub get
- uses: o-murphy/flutpak/.github/actions/generate@main
with:
tag: ${{ github.ref_name }}
metainfo-path: app/share/metainfo/<app_id>.metainfo.xml
artifact-name: flatpak-generated
build:
needs: generate
strategy:
matrix:
arch: [amd64, arm64]
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: flatpak-generated
path: flatpak/generated
- uses: o-murphy/flutpak/.github/actions/build-flatpak@main
id: build
with:
manifest: flatpak/generated/<app_id>.yml
app-id: io.github.YourOrg.YourApp
artifact-name: myapp-${{ matrix.arch }}
github-token: ${{ secrets.GITHUB_TOKEN }}
For a minimal single-job workflow that uses setup-flutpak + manual steps, see
the legacy example below.
Legacy single-job example (manual steps)
name: Flatpak release (manual)
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: o-murphy/flutpak/.github/actions/setup-flutpak@main
- uses: o-murphy/flutpak/.github/actions/flutter@main
with:
flutter-version: stable
cache: true
- run: flutter pub get
- run: flutpak generate --tag ${{ github.ref_name }}
Validating and building locally #
flutpak generates sources and manifests. The actual lint, build, and
validation steps use the official Flatpak toolchain.
Install toolchain #
# Install appstreamcli (Debian/Ubuntu)
sudo apt-get install appstream
# Install org.flatpak.Builder (required for build + lint)
flatpak remote-add --user --if-not-exists flathub \
https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install --user flathub org.flatpak.Builder
# Install the Freedesktop runtime
flatpak install flathub org.freedesktop.Sdk//25.08
1. Validate metainfo #
appstreamcli validate --explain --no-net \
app/share/metainfo/<app_id>.metainfo.xml
2. Lint the manifest #
dbus-run-session flatpak run \
--filesystem=host \
--command=flatpak-builder-lint \
org.flatpak.Builder \
--exceptions \
manifest flatpak/generated/<app_id>.yml
--exceptions applies the built-in Flathub exception list. Run this before
building to catch manifest errors early.
Important
Do not set a top-level branch: in your manifest —
flatpak-builder-lint flags this as toplevel-unnecessary-branch.
3. Build with flathub-build #
flathub-build is the same script Flathub CI uses. It runs flatpak-builder
with --sandbox, --install-deps-from=flathub, --repo=repo, and other
Flathub-specific flags.
dbus-run-session flatpak run --command=flathub-build \
org.flatpak.Builder \
flatpak/generated/<app_id>.yml
4. Lint the built repo #
dbus-run-session flatpak run \
--filesystem=host \
--command=flatpak-builder-lint \
org.flatpak.Builder \
--exceptions \
repo repo
5. Export a single-file bundle (optional) #
flatpak build-bundle repo myapp.flatpak <app_id>
flatpak install --user myapp.flatpak
flatpak run <app_id>
Why include flutter_tools/pubspec.lock? #
Before any flutter command runs inside the Flatpak sandbox, the Flutter
tooling bootstraps itself by running pub get inside
packages/flutter_tools/. This requires the flutter_tools dependencies to be
present in the offline pub cache.
Pass both lock files so the generated sources cover the app and the tool:
pub:
locks:
- pubspec.lock
- $FLUTTER_ROOT/packages/flutter_tools/pubspec.lock
When the same package appears at different versions in the two lock files (e.g.
yaml 3.1.2 in the app and yaml 3.1.3 in flutter_tools), both versions are
included — deduplication is by (name, version) pair.
How it works #
Pub sources #
For each hosted package in your lock file(s), flutpak fetches the SHA-256
checksum from the pub.dev API and generates two flatpak-builder source
entries:
[
{
"type": "archive",
"url": "https://pub.dev/packages/yaml/versions/3.1.2.tar.gz",
"sha256": "abc123...",
"dest": ".pub-cache/hosted/pub.dev/yaml-3.1.2",
"strip-components": 0
},
{
"type": "inline",
"contents": "abc123...",
"dest": ".pub-cache/hosted-hashes/pub.dev",
"dest-filename": "yaml-3.1.2.sha256"
}
]
Both entries are required: pub get --offline checks the hash file and fails
if it is missing even when the archive is present.
Flutter SDK sources #
When flutter.sdk: is configured, flutpak reads the engine version from the
local Flutter install (bin/internal/engine.version, etc.) and constructs
download URLs for each artifact — Dart SDK, engine binaries, fonts, and the
Gradle wrapper — for both x86_64 and aarch64. SHA-256 checksums are cached
in ~/.cache/flutpak/ by URL hash to avoid redundant downloads across runs.
All sources (pub + Flutter SDK) are combined into a single
generated-sources.json. This matches the convention expected by Flathub
reviewers — splitting into multiple files offers no practical benefit and
typically prompts questions during review.
Two extra entries are always added:
sky_engine/pubspec.yaml(inline) —packages/sky_engine/was removed from the Flutter git tree in Flutter 3.x. Written inline sopub get --offlineresolves it.setup-flutter.sh— wires the downloaded artifacts together inside the Flatpak sandbox.
flutpak determines the Flutter version from the SDK path using the following
fallback chain:
<sdk>/version— flat version file present in Flutter < 3.32git describe --tags --abbrev=0— works for any tagged git clone<sdk>/packages/flutter/pubspec.yaml— inner package version field
Patches registry #
Patch injection happens at generate time, not init time. The template
manifest contains no type: patch entries — this is by design. On every
generate run, flutpak resolves the current package versions from
pubspec.lock and injects the correct type: patch entries (with accurate
dest: .pub-cache/hosted/pub.dev/<package>-<version> paths) into the generated
manifest after the generated-sources.json line. Patch files themselves are
committed to flatpak/patches/ and copied to generated/patches/ during
generation.
The built-in Flutter bootstrap patch (shared.sh.patch) replaces
pub upgrade (requires network) with pub get --offline inside the Flutter
SDK's shared.sh bootstrap script. It is injected directly into the generated
manifest's sources: section and applied automatically — no configuration
needed. For pure Dart projects (--pub-only) it is skipped entirely.
Known patches for common packages are maintained as reference files in the
known-patches/ directory of this repository, with usage
instructions in known-patches/PATCHES.md.
Copy the relevant .patch file to your project's flatpak/patches/ directory
and reference it via the patches: config key — flutpak generate will then
copy it to generated/patches/ and inject it into the manifest automatically.
Wrapper script #
For Flutter apps, init generates flatpak/<name>-wrapper.sh:
#!/bin/sh
# Generated by flutpak — https://github.com/o-murphy/flutpak
APP=/app/<name>
export LD_LIBRARY_PATH="$APP/lib:${LD_LIBRARY_PATH:-}"
exec "$APP/<name>" "$@"
This bridges Flatpak's command: entry (pointing to /app/bin/<name>) to the
Flutter bundle at /app/<name>/<name>, setting LD_LIBRARY_PATH for shared
libraries bundled with the app.
Template vs generated #
The template (flatpak/<app_id>.yml) is a valid Flatpak manifest with two
placeholder strings:
__FLATPAK_TAG__— replaced by the git tag (e.g.v1.2.3) or HEAD SHA__FLATPAK_COMMIT__— replaced by the full commit SHA
generate copies the template to flatpak/generated/<app_id>.yml,
substitutes the placeholders, and injects patch sources immediately after
the generated-sources.json reference. Patches are never baked into the
template — they are resolved from pubspec.lock at generate time so the
dest: path always contains the correct package version. The template is
never modified; the generated file is gitignored and rebuilt on every CI run.
generate also validates consistency between the template and config before
writing anything:
app-idin template must matchmanifest.app_idin configcommandin template must matchmanifest.commandin config (or its default)runtime-versionin template must matchmanifest.runtime_versionin config
Building from source / contributing #
git clone https://github.com/o-murphy/flutpak.git
cd flutpak
make test # run test suite
make build # regenerate version.dart + compile binary
make version # regenerate version.dart only
Bumping the version #
- Update
version:inpubspec.yaml - Run
make version(ordart run tool/update_version.dart) — rewriteslib/src/version.dart - Commit both files
During a release, release.yml performs steps 1–3 automatically when a v*
tag is pushed, so the compiled binaries always report the correct version.
License #
MIT