mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-10 22:12:49 +00:00
docs: add MSIX Store build design spec
This commit is contained in:
177
docs/superpowers/specs/2026-06-11-msix-store-build-design.md
Normal file
177
docs/superpowers/specs/2026-06-11-msix-store-build-design.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# MSIX Microsoft Store Build — Design
|
||||
|
||||
Date: 2026-06-11. Status: approved (design review with maintainer).
|
||||
Planning/requirements background: `MSIX_STORE_HANDOFF.md` (repo root,
|
||||
validated against Microsoft Learn docs and Store Policies v7.19).
|
||||
|
||||
## Goal
|
||||
|
||||
Produce an unsigned `.msix` of OrcaSlicer in CI, built from the same
|
||||
Windows install tree as the NSIS installer, suitable for manual upload to
|
||||
Partner Center. The Store re-signs with Microsoft's certificate, which
|
||||
makes the Store build install cleanly on Smart App Control (SAC) machines
|
||||
that block the unsigned NSIS installer.
|
||||
|
||||
Everything is additive: existing build outputs (NSIS exe, portable zip)
|
||||
are untouched, and every runtime behavior change is gated behind a
|
||||
packaged-context check so classic builds behave exactly as today.
|
||||
|
||||
## Decisions (already made)
|
||||
|
||||
- Packaging path: hand-written `AppxManifest.xml` + `makeappx pack` over
|
||||
the existing install tree. No CPack MSIX generator exists.
|
||||
- Minimum Windows: 10 1903 (`MinVersion 10.0.18362.0`), declaring BOTH
|
||||
virtualization elements (Win11 fine-grained exclusion + Win10 coarse
|
||||
disable). Each OS honors the one it supports.
|
||||
- Network plugin: keep the runtime downloader, do NOT bundle Bambu's
|
||||
closed-source DLLs in the package.
|
||||
- Config stays at the real `%APPDATA%\OrcaSlicer` via manifest
|
||||
virtualization exclusions + `unvirtualizedResources` restricted
|
||||
capability. No `data_dir` code changes.
|
||||
- Submission is manual via Partner Center (first submission must be);
|
||||
CI only produces the artifact.
|
||||
|
||||
## Components
|
||||
|
||||
### 1. `scripts/msix/` — packaging files (new)
|
||||
|
||||
Precedent: platform packaging already lives under `scripts/` (flatpak).
|
||||
|
||||
**`AppxManifest.xml`** — template with four substitution tokens:
|
||||
`@MSIX_VERSION@`, `@MSIX_IDENTITY_NAME@`, `@MSIX_PUBLISHER@`,
|
||||
`@MSIX_PUBLISHER_DISPLAY_NAME@` (all three identity strings must match
|
||||
the Partner Center-assigned values exactly).
|
||||
Key contents (exact schema/namespace details verified against the MSIX
|
||||
schema reference during implementation; `makeappx`/WACK validate):
|
||||
- `TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0"`.
|
||||
- Capabilities: `runFullTrust` + `rescap:unvirtualizedResources`.
|
||||
- Under `Properties`, both virtualization elements:
|
||||
- `virtualization:FileSystemWriteVirtualization` with
|
||||
`ExcludedDirectory = $(KnownFolder:RoamingAppData)\OrcaSlicer`
|
||||
(Windows 11 fine-grained), and
|
||||
- `desktop6:FileSystemWriteVirtualization = disabled`
|
||||
(Windows 10 1903+ coarse fallback).
|
||||
- `Application Executable="orca-slicer.exe"
|
||||
EntryPoint="Windows.FullTrustApplication"` (launcher output name set
|
||||
at `src/CMakeLists.txt:189`).
|
||||
- Extensions:
|
||||
- `windows.fileTypeAssociation` for `.3mf`, `.stl`, `.step`/`.stp`,
|
||||
`.gcode`. Note: `.gcode` is opt-in in the classic build
|
||||
(`associate_gcode`); manifest declarations are static, so it is
|
||||
always declared. Declaring an FTA only adds OrcaSlicer to "Open
|
||||
with" — the user controls defaults via Windows Settings, so this is
|
||||
not a behavior regression.
|
||||
- `windows.protocol` for `orcaslicer://`.
|
||||
- `rescap3:MigrationProgIds` declaring `Orca.Slicer.1`.
|
||||
KNOWN LIMITATION: the classic build writes its ProgID with a
|
||||
leading space (`L" Orca.Slicer.1"`, `GUI_App.cpp:9119`), which
|
||||
MigrationProgIds cannot express. Migration hand-off from existing
|
||||
NSIS installs may therefore be partial; Windows shows both apps in
|
||||
"Open with" and the user picks once. The legacy ProgID is NOT fixed
|
||||
in this change (separate change with its own migration risk).
|
||||
|
||||
**`assets/`** — committed PNGs generated once from
|
||||
`resources/images/OrcaSlicer.svg`: Square44x44Logo, Square150x150Logo,
|
||||
StoreLogo (50x50), plus standard scale variants. Committed rather than
|
||||
generated in CI so the pack step has no extra tool dependencies.
|
||||
|
||||
**`build_msix.ps1`** — single script, runnable in CI and locally (needs
|
||||
Windows SDK for `makeappx`):
|
||||
|
||||
1. Parse `version.inc` `SoftFever_VERSION` (`2.4.0-dev` → `2.4.0.0`;
|
||||
MAJOR.MINOR.PATCH from the leading semver triplet, revision fixed
|
||||
at 0 as the Store requires).
|
||||
2. Stage: copy the install tree (`build/OrcaSlicer`) + token-substituted
|
||||
manifest + `assets/` into a temp layout.
|
||||
3. `makeappx pack` → `OrcaSlicer_Windows_MSIX_<version>.msix`.
|
||||
|
||||
Parameters: `-InstallDir`, `-OutputPath`, `-IdentityName`, `-Publisher`,
|
||||
`-PublisherDisplayName` (identity defaults are obvious placeholders). NO signing — the Store
|
||||
strips and re-signs; local testing uses Developer Mode loose-layout
|
||||
registration instead.
|
||||
|
||||
### 2. CI — `.github/workflows/build_orca.yml`
|
||||
|
||||
One new step in the Windows job, after the install tree exists (adjacent
|
||||
to the portable-zip step): run `build_msix.ps1`, upload the `.msix` as a
|
||||
workflow artifact. Identity comes from repo variables
|
||||
(`vars.ORCA_MSIX_IDENTITY_NAME`, `vars.ORCA_MSIX_PUBLISHER`,
|
||||
`vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME`); when unset,
|
||||
placeholder defaults still produce a valid artifact (not Store-uploadable,
|
||||
which is fine pre-approval). The step must not fail the job when repo
|
||||
variables are absent (forks).
|
||||
|
||||
### 3. Runtime changes (Windows-only, packaged-context-gated)
|
||||
|
||||
**New helper** — `bool is_running_in_msix()` in
|
||||
`src/slic3r/GUI/GUI_Utils.{hpp,cpp}`: cached null-buffer
|
||||
`GetCurrentPackageFullName` probe (`ERROR_INSUFFICIENT_BUFFER` ⇒
|
||||
packaged, `APPMODEL_ERROR_NO_PACKAGE` ⇒ not); constant `false` on
|
||||
non-Windows.
|
||||
|
||||
**Updater suppression (R4)** — Store apps must not self-update:
|
||||
|
||||
- Skip the startup auto-check (`check_new_version_sf()` call at
|
||||
`GUI_App.cpp:934`) when packaged.
|
||||
- The manual "Check for updates" menu action (`MainFrame.cpp:2580`)
|
||||
opens the Store listing (`ms-windows-store://pdp/?ProductId=...`,
|
||||
ProductId from a build-time define fed by repo variable
|
||||
`ORCA_MSIX_STORE_PRODUCT_ID`) instead of the download flow. If the
|
||||
ProductId is not configured (pre-reservation builds), the menu action
|
||||
shows a message that updates are delivered through the Microsoft
|
||||
Store — it never falls back to the classic download flow.
|
||||
|
||||
**Association suppression (R3)** — the manifest owns shell integration;
|
||||
runtime registry writes are virtualized and invisible:
|
||||
|
||||
- Early-return in `associate_files`, `disassociate_files`,
|
||||
`associate_url`, `disassociate_url` when packaged.
|
||||
- Hide the file-association checkboxes in Preferences
|
||||
(`Preferences.cpp:982+`) in packaged context.
|
||||
- Suppress any prompt/check that offers to (re)register associations
|
||||
(e.g. `check_url_association` consumers) in packaged context —
|
||||
implementation enumerates call sites.
|
||||
|
||||
## What does NOT change
|
||||
|
||||
- `data_dir` / config location code — `%APPDATA%\OrcaSlicer` everywhere.
|
||||
- NSIS/CPack packaging, portable zip, all non-Windows builds.
|
||||
- Bambu network plugin download flow (works against the real AppData
|
||||
path; SAC behavior verified per the test plan).
|
||||
- Classic-build association/updater behavior (gates are packaged-only).
|
||||
|
||||
## Verification
|
||||
|
||||
No meaningful unit-test surface (Windows shell + packaging behavior);
|
||||
the PR documents manual verification per repo review guidelines:
|
||||
|
||||
1. Local loose-layout install (Developer Mode,
|
||||
`Add-AppxPackage -Register AppxManifest.xml` over the staged layout):
|
||||
app launches; `.3mf` open-with and `orcaslicer://` activation work;
|
||||
single-instance hand-off works when launched via the package alias.
|
||||
2. Config interop: profiles created by a classic install are visible in
|
||||
the packaged app and vice versa (Win11 machine); profiles survive
|
||||
packaged-app uninstall.
|
||||
3. Updater: no startup check; menu action opens Store listing.
|
||||
4. Network plugin: download + load succeeds in packaged context.
|
||||
5. WACK run against the CI artifact passes (or failures triaged).
|
||||
6. CI: Windows job produces the `.msix` artifact with correct version;
|
||||
NSIS and portable artifacts byte-identical in content to before
|
||||
(spot-check).
|
||||
7. Post-certification only: SAC end-to-end test via private-audience
|
||||
listing (cannot be done locally; Store signature is the variable
|
||||
under test).
|
||||
|
||||
## Sequencing / rollout
|
||||
|
||||
The PR lands before Partner Center account approval — placeholder
|
||||
identity builds a valid artifact. Once the account clears and the app
|
||||
name is reserved, set the three repo variables (identity name, publisher
|
||||
`CN=<GUID>`, ProductId); the next CI run produces the uploadable
|
||||
package. First Store submission is manual (listing, IARC,
|
||||
`runFullTrust` + `unvirtualizedResources` justifications) per the
|
||||
handoff doc's "Submission process" section.
|
||||
|
||||
Main external risk (tracked in handoff doc R2.5): Store approval of
|
||||
`unvirtualizedResources` for a non-game app is not guaranteed; fallback
|
||||
is documented there and does not change this design's code shape.
|
||||
Reference in New Issue
Block a user