Files
punktfunk/crates/punktfunk-client-windows/packaging/README.md
T
enricobuehler bb11b2faf7
apple / swift (push) Successful in 54s
ci / rust (push) Failing after 55s
windows-msix / package (push) Successful in 1m2s
ci / web (push) Successful in 31s
windows / build (push) Successful in 55s
ci / docs-site (push) Successful in 31s
android / android (push) Successful in 2m6s
deb / build-publish (push) Successful in 2m24s
decky / build-publish (push) Successful in 11s
ci / bench (push) Successful in 4m21s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m39s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m32s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m49s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 1m21s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 3m20s
docker / deploy-docs (push) Successful in 22s
feat(windows): MSIX packaging + publish workflow for the WinUI client
Package the Windows client as a signed MSIX (Start tile, clean install/uninstall) and publish it to
Gitea's generic registry, mirroring the host's .deb/.rpm and the Mac's DMG. Validated end-to-end on
the build VM: cargo build --release -> makeappx pack (16 payload files, 58 MB) -> signtool ->
Add-AppxPackage deploy -> framework-dependency resolution all green.

- packaging/AppxManifest.xml: full-trust Win32 app (Windows.FullTrustApplication + runFullTrust),
  templated {VERSION}/{PUBLISHER}. windows-reactor packages cleanly despite being built "unpackaged"
  because it calls MddBootstrapInitialize2 with OnPackageIdentity_NOOP — under MSIX identity the
  bootstrapper no-ops and the App SDK resolves from the manifest's PackageDependency on
  Microsoft.WindowsAppRuntime.2 (reactor pins MAJORMINOR 0x20000 = 2.0).
- packaging/pack-msix.ps1: assemble layout (exe + reactor/SDL3 auto-staged DLLs + resources.pri +
  FFmpeg DLLs + tile assets), makeappx, signtool. Cert precedence: MSIX_CERT_PFX_B64 secret, else an
  ephemeral self-signed cert whose .cer is published alongside (swap in a real cert later, no
  manifest change).
- assets: tile/store logos rasterized from packaging/flatpak/io.unom.Punktfunk.svg.
- .gitea/workflows/windows-msix.yml: runs on the Windows runner on main pushes + win-v* tags +
  dispatch. MSIX version is 4-part numeric — win-vX.Y.Z -> X.Y.Z.0, else 0.2.<run>.0. shell: pwsh +
  CARGO_TARGET_DIR=C:\t like windows.yml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 08:45:43 +00:00

72 lines
3.6 KiB
Markdown

# punktfunk Windows client — MSIX packaging
The Windows client ships as a **signed MSIX** so Windows boxes get a real package (Start tile,
clean install/uninstall) instead of a loose exe. CI builds + publishes it from
[`.gitea/workflows/windows-msix.yml`](../../../.gitea/workflows/windows-msix.yml) to Gitea's
**generic** package registry (`https://git.unom.io/unom/-/packages`), on every `main` push that
touches the client and on `win-v*` release tags.
## What's in the package
`pack-msix.ps1` assembles a layout from a `cargo build --release` and runs `makeappx` + `signtool`:
| File | Source |
|---|---|
| `punktfunk-client.exe` | the release build |
| `Microsoft.WindowsAppRuntime.Bootstrap.dll`, `resources.pri` | auto-staged by windows-reactor's `build.rs` |
| `SDL3.dll` | auto-staged by the `sdl3` crate |
| `avcodec/avformat/avutil/swscale/swresample/...-*.dll` | `FFMPEG_DIR\bin` |
| `Assets\*.png` | checked-in tile/store logos (rasterized from `packaging/flatpak/io.unom.Punktfunk.svg`) |
| `AppxManifest.xml` | the template here, with `{VERSION}`/`{PUBLISHER}` substituted |
### Why an "unpackaged" WinUI app packages cleanly
windows-reactor calls `MddBootstrapInitialize2` with `OnPackageIdentity_NOOP`
(`crates/libs/reactor/src/app.rs`), so under MSIX **package identity** the App SDK bootstrapper is
a no-op and the runtime is resolved from the manifest's `<PackageDependency>` on
`Microsoft.WindowsAppRuntime.2` instead (reactor pins `WINDOWSAPPSDK_RELEASE_MAJORMINOR = 0x20000`
= 2.0). It's a full-trust Win32 app (`EntryPoint="Windows.FullTrustApplication"` + `runFullTrust`)
because it owns raw D3D11, Win32 low-level input hooks, WASAPI and SDL3.
## Versioning
MSIX requires a strictly 4-part numeric version. The workflow computes:
- `win-vX.Y.Z` tag → `X.Y.Z.0` (a real client release; `win-v*` is its own tag namespace, kept off
the host's `host-v*` and Apple's `v*` to avoid the version-shadow bug).
- `main` push / `workflow_dispatch``0.2.<run_number>.0` (rolling, climbs by run number).
## Signing & install
Signing precedence in `pack-msix.ps1`:
1. **`MSIX_CERT_PFX_B64` / `MSIX_CERT_PASSWORD`** Actions secrets — a real (or shared) code-signing
`.pfx` whose **subject DN must equal `-Publisher`** (default `CN=unom`). Drop these in later to
move off self-signed with **no manifest change**; if the cert's subject differs, pass a matching
`-Publisher` (it's stamped into the manifest `Identity`).
2. otherwise an **ephemeral self-signed** cert (subject = `-Publisher`) is generated and its public
`.cer` is published next to the `.msix`.
To install a self-signed build, trust the cert once, then add the package:
```powershell
Import-Certificate -FilePath .\punktfunk-client-windows_<ver>_x64.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople
Add-AppxPackage -Path .\punktfunk-client-windows_<ver>_x64.msix
```
The MSIX declares a dependency on the Windows App SDK 2.x runtime; install
[the App SDK runtime](https://aka.ms/windowsappsdk) if `Add-AppxPackage` reports a missing
`Microsoft.WindowsAppRuntime.2` framework.
## Building locally
On the Windows runner / dev VM (MSVC + Windows SDK present), after a release build:
```powershell
cargo build --release -p punktfunk-client-windows
pwsh -File crates/punktfunk-client-windows/packaging/pack-msix.ps1 `
-Version 0.2.0.0 -TargetDir C:\t\release -OutDir C:\t\msix
```
Validated end-to-end on the build VM (pack → sign → `Add-AppxPackage` → framework-dependency
resolution). The only step that needs a real display is *launching* the WinUI window (same
on-glass constraint as the rest of the client).