Skip to content

ShellHost & Launcher: hot-load signed game frameworks from Documents/Frameworks - #1217

Merged
LNPANDY merged 1 commit into
mainfrom
feat/ios-hot-framework-load
Nov 12, 2026
Merged

LNPANDY merged 1 commit into
mainfrom
feat/ios-hot-framework-load

Conversation

@LNPANDY

@LNPANDY LNPANDY commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Summary

Part 4 of the 4-PR patch queue slimming and shared-app delivery stack (stacked on #1216, following #1214 and #1215).

Lands fast hot-framework loading and delivery inspired by #1165 with zero new engine patches and zero extra Swift packages:

  1. Atomic Documents/Frameworks discovery and promotion (GameCatalogue, ShellHostModel):
    • GameCatalogue.promoteStagedFrameworks(in:) verifies .staging-<ID>-<token>/.ready (schema: 1, titleID, regular file count, and byte total) before atomically promoting DmGame<ID>.framework into Documents/Frameworks/. Incomplete transfers without .ready stay untouched while recent, and damaged stagings are discarded safely.
    • GameCatalogue.scan(root:hotRoot:) merges writable Documents/Frameworks/ bundles with read-only DmShell.app/Frameworks/ bundles: a newer hot build overrides an older bundled copy, whereas a later full app build or re-sign that embeds an equal or newer built_at automatically reclaims the redundant hot copy from Documents/Frameworks/.
    • Deleting a game in ShellHostModel physically removes its writable Documents/Frameworks/DmGame<ID>.framework bundle and suppresses any older bundled copy in DmShell.app/Frameworks/. Returning to the foreground refreshes the library so newly pushed games appear right away.
  2. Crash-free Mach-O code-signature and Team ID preflight (ProvisioningProfile, ShellApp.swift, ShellMain.m):
    • At launch, DmShell writes Documents/.shell-host.json off the main thread with its bundle ID, signing team ID, glue ABI version, shader chain, and provisioning expiration epoch.
    • Before dlopen, FrameworkSignature.preflightExternal inspects the external Mach-O LC_CODE_SIGNATURE SuperBlob and CS_CodeDirectory teamOffset in user space: team-signed hosts reject unsigned or mismatched-team external frameworks with a localized 10-language message instead of hitting a fatal EXC_BAD_ACCESS (CODESIGNING) kernel kill on non-JIT iOS, while TrollStore / profile-less installs accept ad-hoc signed frameworks directly.
    • On physical iOS devices, ShellMain.m also registers external signatures via F_ADDFILESIGS_RETURN before dlopen and blocks re-entering a hot-updated framework inside the same running process with a clean restart prompt.
  3. ~2-second direct framework signing and hot push on macOS (ShellHotInstall, ShellInstall, ShellInstall+Batch):
    • Across install, installBuilt, and multi-game installBatch, when DmShell is already installed on the paired device under the same signing team (Documents/.shell-host.json), at least 24 hours remain on its provisioning profile, this Mac holds the matching Apple Development certificate, and the built framework carries its own host (loader == "FH"), ShellInstaller signs DmGame<ID>.framework directly with codesign and copies it to Documents/Frameworks/.staging-<ID>-<token>/ followed by .ready as the final step, skipping xcodebuild and full .app reinstallation.
    • First-time installs, team mismatches, profiles within 24 hours of expiry (renewing 7-day free Apple ID signatures), missing local certificates, or any copy error fall back automatically to the full xcodebuild + devicectl device install app pipeline.

Verification

  • python3 tools/engine.py check -> 42 patches apply cleanly (0 new patches added).
  • python3 tools/l10n_shell_catalogs.py --check and test_localization_rules.py -> all 10 language JSON files and Localizable.xcstrings verified.
  • swift test --package-path frontend-ios --filter "HotFrameworkTests|ShellStringsTests|GameDeletionTests" -> PASS (including real clang -dynamiclib + codesign Mach-O signature inspection tests and negative verification).
  • swift test --package-path frontend --filter "ShellHotInstallTests|ShellInstallTests|SourceSizeTests" -> PASS (including all 5 fallback boundaries, install / installBuilt / installBatch coverage, < 800 line limit check, and negative verification).
  • python3 -m unittest frontend-qt/tests/test_swift_parity.py -> real build_shell.sh iOS DmShell.app template compilation PASS.

@github-actions github-actions Bot added launcher The NX2Apple launcher app ios iPhone or iPad windows Windows (the Qt front end) patch-queue Changes the patch queue or the upstream pin labels Nov 12, 2026
@LNPANDY
LNPANDY force-pushed the feat/ios-hot-framework-load branch from 699fc00 to 4b6b2b0 Compare November 12, 2026 16:06
@v0lumehi v0lumehi modified the milestones: v1.4.0, v1.5.0, v1.6.0 Nov 12, 2026
…Frameworks

Promote staged game frameworks inside Documents/Frameworks atomically once .ready matches the signed file count and byte total, merge writable hot frameworks with bundled frameworks while reclaiming redundant copies after a full rebuild or re-sign, inspect Mach-O LC_CODE_SIGNATURE and team IDs before dlopen to avoid fatal codesigning kills on non-JIT iOS, and add ~2-second direct codesign plus hot delivery across macOS install, installBuilt, and installBatch with automatic fallback to xcodebuild.
@LNPANDY
LNPANDY force-pushed the feat/shared-ipa-repack-and-ext-msl branch from 0a36e25 to 0d9e398 Compare November 12, 2026 19:45
@LNPANDY
LNPANDY force-pushed the feat/ios-hot-framework-load branch from 4b6b2b0 to 2b1615e Compare November 12, 2026 19:45
@LNPANDY
LNPANDY changed the base branch from feat/shared-ipa-repack-and-ext-msl to main November 12, 2026 20:07
@LNPANDY
LNPANDY merged commit 2ff3220 into main Nov 12, 2026
19 of 33 checks passed
@LNPANDY
LNPANDY deleted the feat/ios-hot-framework-load branch November 12, 2026 20:08
LNPANDY added a commit that referenced this pull request Nov 12, 2026
Bump AppUpdateStore.appVersion and Qt APP_VERSION to 1.5.0 and add CHANGELOG.md, CHANGELOG.zh-CN.md, and bilingual release-notes/v1.5.0.md entries covering PRs #1214, #1215, #1216, #1217, #1226, and #1227.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ios iPhone or iPad launcher The NX2Apple launcher app patch-queue Changes the patch queue or the upstream pin windows Windows (the Qt front end)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants