flutpak 0.2.8
flutpak: ^0.2.8 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.
Analogous to flutter pub run build_runner build — describe your config once
in pubspec.yaml and let flutpak prepare generate everything needed for a
Flathub-compatible offline build.
- One command —
flutpak preparegenerates sources, resolves patches, and creates/updates the manifest - No Python — pure Dart, compiles to a single native binary for CI
- Config in
pubspec.yaml— same pattern asmsix_config,flutter_native_splash - Manifest generation — writes
flatpak/<app_id>.ymlwith__FLATPAK_TAG__/__FLATPAK_COMMIT__placeholders that CI patches - Patches registry — known packages (e.g.
objectbox_flutter_libs) get their patches resolved automatically - Retry on transient errors — pub.dev and Flutter artifact downloads retry on 429/5xx
Installation #
dart pub global activate flutpak
Or compile a native binary (for CI without a Dart SDK):
git clone --depth 1 https://github.com/o-murphy/flutpak.git /tmp/flutpak_src
cd /tmp/flutpak_src && dart pub get
dart compile exe bin/flutpak.dart -o /tmp/flutpak
Quick start #
1. Add config to pubspec.yaml #
flutpak:
output: flatpak
flutter_version_file: flatpak/flutter.version # optional
pub:
locks:
- pubspec.lock
- $FLUTTER_ROOT/packages/flutter_tools/pubspec.lock
flutter:
sdk: $FLUTTER_ROOT
manifest:
app_id: io.github.YourOrg.YourApp
runtime_version: "25.08"
command: yourapp
repo_url: https://github.com/YourOrg/YourApp.git
finish_args:
- --share=ipc
- --socket=wayland
- --device=dri
2. First run — generate everything #
FLUTTER_ROOT=/path/to/flutter flutpak prepare
This creates:
flatpak/io.github.YourOrg.YourApp.yml— manifest with__FLATPAK_TAG__/__FLATPAK_COMMIT__placeholdersflatpak/generated-sources.json— pub packages + Flutter SDK artifactsflatpak/patches/— patch files from the built-in registry (if needed)flatpak/flutter.version— pinned Flutter version string (ifflutter_version_fileset)
Commit the generated files to git. The manifest is a generated artifact (like *.g.dart from build_runner) that you check in for Flathub review.
3. CI: pin tag/commit and regenerate sources #
flutpak prepare \
--tag "$TAG" \
--commit "$COMMIT_SHA" \
--sdk "$FLUTTER_ROOT"
This replaces __FLATPAK_TAG__ / __FLATPAK_COMMIT__ in the manifest and regenerates generated-sources.json.
Full config reference #
Config lives in one of two places (error if both exist):
| Location | Key |
|---|---|
pubspec.yaml |
flutpak: section |
flutpak.yaml |
standalone file |
flutpak:
output: flatpak # output directory for all generated files (default: flatpak)
flutter_version_file: flatpak/flutter.version # optional: write Flutter version here
pub:
locks:
- pubspec.lock
- $FLUTTER_ROOT/packages/flutter_tools/pubspec.lock # $ENV vars are expanded
flutter:
sdk: $FLUTTER_ROOT
patch: flatpak/patches/flutter/shared.sh.patch # optional: custom shared.sh patch
patches: # project-level patches for pub packages
- package: objectbox_flutter_libs
path: flatpak/patches/objectbox_flutter_libs/CMakeLists.txt.patch
dest_subpath: linux # optional: subdir within the pub package root
# version: 5.3.1 # optional: auto-resolved from pubspec.lock if omitted
manifest:
app_id: io.github.YourOrg.YourApp
runtime_version: "25.08"
sdk_extensions:
- org.freedesktop.Sdk.Extension.llvm20 # auto-adds llvm bin/lib to PATH
command: yourapp
repo_url: https://github.com/YourOrg/YourApp.git
finish_args:
- --share=ipc
- --socket=fallback-x11
- --socket=wayland
- --device=dri
extra_modules:
- flatpak/modules/some-native-dep.yml # included verbatim in modules list
env: # build-options env vars (shorthand)
MY_VAR: value
build_options:
append_path: /custom/bin # appended to PATH
prepend_ld_library_path: /custom/lib # prepended to LD_LIBRARY_PATH
env: # merged with top-level env:
ANOTHER_VAR: value
extra_sources: # verbatim flatpak sources (arch-specific archives, etc.)
- type: archive
only-arches:
- x86_64
url: https://github.com/example/lib/releases/download/v1.0/lib-linux-x64.tar.gz
sha256: abc123...
dest: lib-prebuilt
strip-components: 0
- type: archive
only-arches:
- aarch64
url: https://github.com/example/lib/releases/download/v1.0/lib-linux-aarch64.tar.gz
sha256: def456...
dest: lib-prebuilt
strip-components: 0
Required project structure #
The generated manifest expects the following files to be present in your repository.
flutpak prepare installs them into /app/share/ inside the Flatpak sandbox using
install -Dm644, so a missing file will cause the build to fail with a clear error.
app/
└── share/
├── applications/
│ └── <app_id>.desktop # XDG desktop entry
├── icons/
│ └── hicolor/
│ └── 512x512/
│ └── apps/
│ └── <app_id>.png # application icon (512×512 PNG)
└── metainfo/
└── <app_id>.metainfo.xml # AppStream metainfo
These files must be committed to git — they are read directly from the source tree
during the Flatpak build. flutpak does not generate them.
Patches registry #
flutpak ships a built-in registry of patches for packages that need special
handling inside the Flatpak sandbox. Patches are applied automatically when the
package is found in any of your lock files.
| Package | What the patch does |
|---|---|
objectbox_flutter_libs |
Replaces prebuilt binary download with a local objectbox-c archive |
sqflite_common_ffi |
Adjusts CMake for sandbox builds |
Project-level patches: entries always take priority over registry entries for
the same package.
Commands #
prepare (recommended) #
One-shot command — generates sources, resolves patches, and creates or updates the manifest.
# First run: generate everything from scratch
flutpak prepare
# CI: update placeholders + regenerate sources
flutpak prepare --tag v1.2.3 --commit abc1234567890 --sdk "$FLUTTER_ROOT"
| Flag | Description |
|---|---|
--tag |
Git tag embedded in the manifest (e.g. v0.1.14). Omit to remove the tag: line. |
--commit |
Full git commit SHA. Defaults to git rev-parse HEAD. |
-s, --sdk |
Flutter SDK path. Defaults to $FLUTTER_ROOT. |
--no-sources |
Skip source regeneration (manifest update only). |
--pub-only |
Skip Flutter SDK sources, generate only pub packages. |
--flutter-only |
Skip pub sources, generate only Flutter SDK artifacts. |
-n, --dry-run |
Print what would be done without writing any files. |
-c, --config |
Path to config file (default: flutpak.yaml). |
Workflow:
pubspec.yaml [flutpak: ...]
↓
flutpak prepare # first run: generates everything
↓
flatpak/<app_id>.yml # manifest with __FLATPAK_TAG__ / __FLATPAK_COMMIT__
flatpak/generated-sources.json # pub packages + Flutter SDK artifacts
flatpak/patches/ # patches from registry (if applicable)
↓
git commit + push
↓
CI: flutpak prepare --tag $TAG --commit $SHA --sdk $FLUTTER_ROOT
↓
flatpak-builder build --repo=...
sources #
Generates generated-sources.json combining pub packages and Flutter SDK.
flutpak sources \
--lock pubspec.lock \
--lock "$FLUTTER_ROOT/packages/flutter_tools/pubspec.lock" \
--sdk "$FLUTTER_ROOT" \
--output flatpak
generated-sources.json is always written as <output>/generated-sources.json.
| Flag | Description |
|---|---|
-l, --lock |
pubspec.lock path (repeatable, $ENV expanded) |
-s, --sdk |
Flutter SDK path |
-o, --output |
Output directory (default: flatpak) |
--pub-only |
Skip Flutter SDK sources |
--flutter-only |
Skip pub sources |
pub #
Generates sources for pub packages only.
flutpak pub --lock pubspec.lock --output flatpak
flutter #
Generates sources for Flutter SDK artifacts only.
flutpak flutter --sdk "$FLUTTER_ROOT" --output flatpak
sdk-ext #
Generates a Flathub SDK Extension manifest (org.freedesktop.Sdk.Extension.flutter3)
to share the Flutter SDK across multiple apps on the same machine.
flutpak sdk-ext \
--sdk "$FLUTTER_ROOT" \
--runtime-version 25.08 \
--output org.freedesktop.Sdk.Extension.flutter3.json
CI/CD integration #
GitHub Actions — composite action (recommended) #
The pin-manifest composite action handles Flutter SDK setup, binary download,
and flutpak prepare in one step. Add it to your release workflow:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Pin Flatpak manifest
uses: o-murphy/flutpak/.github/actions/pin-manifest@main
with:
tag_name: ${{ github.ref_name }} # e.g. v1.2.3
flutter_version_file: flatpak/flutter.version # committed version file
# flutter_version: stable # or explicit version
# config: flutpak.yaml # default: auto-detected
| Input | Description |
|---|---|
tag_name |
Tag to embed in the manifest (required) |
flutter_version |
Flutter SDK version (e.g. stable, 3.41.9) |
flutter_version_file |
Path to committed version file (one of these two required) |
commit |
Commit SHA (default: resolved from tag) |
config |
Path to config file (default: auto-detected from CWD) |
flutpak_version |
flutpak release tag to download (default: latest) |
cache |
Cache Flutter SDK between runs (default: true) |
GitHub Actions — manual #
- name: Build flutpak
run: |
git clone --depth 1 https://github.com/o-murphy/flutpak.git /tmp/flutpak_src
cd /tmp/flutpak_src && dart pub get
dart compile exe bin/flutpak.dart -o /tmp/flutpak
- name: Prepare Flatpak sources and manifest
run: |
REF_TYPE="${{ github.ref_type }}"
TAG=""
if [ "$REF_TYPE" = "tag" ]; then TAG="${{ github.ref_name }}"; fi
/tmp/flutpak prepare \
--tag "$TAG" \
--commit "${{ github.sha }}" \
--sdk "$FLUTTER_ROOT"
Building and validating with official Flatpak tools #
flutpak generates sources and manifests. The actual build, lint, and validation
steps use the official Flatpak toolchain — org.flatpak.Builder (installed as a
Flatpak) and appstreamcli (system package).
Prerequisites #
# 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
1. Validate metainfo (AppStream XML) #
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/<app_id>.yml
--exceptions— apply the built-in Flathub exception list--filesystem=host— lets the sandboxed linter read files from the host- Run this before building to catch manifest errors early
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. The built app is exported to repo/ automatically.
dbus-run-session flatpak run --command=flathub-build org.flatpak.Builder \
flatpak/<app_id>.yml
Note: do not set a top-level
branch:in your manifest —flatpak-builder-lintflags this astoplevel-unnecessary-branch.
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, for local testing) #
flatpak build-bundle repo myapp.flatpak <app_id>
flatpak install --user myapp.flatpak
flatpak run <app_id>
Full GitHub Actions example #
- name: Install flatpak and appstream
run: sudo apt-get install -y flatpak appstream
- name: Validate metainfo
run: |
appstreamcli validate --explain --no-net \
app/share/metainfo/<app_id>.metainfo.xml
- name: Cache org.flatpak.Builder
uses: actions/cache@v5
with:
path: ~/.local/share/flatpak
key: flatpak-builder-25.08-${{ runner.arch }}-v1
- name: Install org.flatpak.Builder
run: |
flatpak remote-add --user --if-not-exists flathub \
https://dl.flathub.org/repo/flathub.flatpakrepo
dbus-run-session flatpak install --user -y --noninteractive flathub \
org.flatpak.Builder
- name: Lint manifest
run: |
dbus-run-session flatpak run \
--filesystem=host \
--command=flatpak-builder-lint \
org.flatpak.Builder \
--exceptions \
manifest flatpak/<app_id>.yml
- name: Build Flatpak
run: |
dbus-run-session flatpak run --command=flathub-build \
org.flatpak.Builder \
flatpak/<app_id>.yml
- name: Lint repo
run: |
dbus-run-session flatpak run \
--filesystem=host \
--command=flatpak-builder-lint \
org.flatpak.Builder \
--exceptions \
repo repo
- name: Export bundle
run: |
flatpak build-bundle repo myapp.flatpak <app_id>
Why include flutter_tools/pubspec.lock? #
Before any flutter command runs, the Flutter tooling bootstraps itself by running
pub get inside packages/flutter_tools/. This requires 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 (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 packages #
For each hosted package, flutpak fetches the SHA-256 from the pub.dev API and
generates two flatpak source entries:
[
{
"type": "archive",
"url": "https://pub.dartlang.org/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's missing even when the archive is present.
Flutter SDK artifacts #
Reads version files from a local Flutter install (bin/internal/engine.version, etc.)
and constructs download URLs for each artifact (Dart SDK, engine binaries, fonts,
Gradle wrapper). SHA-256 checksums are cached in ~/.cache/flutpak/ by URL hash to
avoid redundant downloads across runs.
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. -
shared.sh.patch— Flutter's bootstrap script runspub upgrade(requires network). The built-in patch replaces it withpub get --offline. Written toflatpak/patches/flutter/shared.sh.patchnext to the output file.
License #
MIT