* feat: integrate Sparkle 2 for auto-update
Adds the standard pieces for Sparkle-based silent updates:
- Package.swift: add Sparkle 2 SPM dep, wired into OpenLessApp.
- Sources/OpenLessApp/Updater/UpdaterController.swift: thin wrapper
around SPUStandardUpdaterController. Owned by AppDelegate so the
updater starts on app launch.
- AppDelegate: instantiate UpdaterController before installing the
main menu; pass it to ApplicationMenu so the menu item can target
it.
- ApplicationMenu: add "检查更新…" as the first item in the OpenLess
menu when an UpdaterController target is present.
- scripts/build-app.sh: copy Sparkle.framework (with Updater.app +
XPC services + Autoupdate) from the SPM artifacts dir into
Contents/Frameworks/, inject SUFeedURL / SUPublicEDKey /
SUEnableAutomaticChecks / SUEnableInstallerLauncherService /
SUScheduledCheckInterval into Info.plist, and ad-hoc sign the
embedded helpers explicitly (deep sign alone is unreliable for
Sparkle's nested XPC bundles).
- scripts/release.sh: one-shot release pipeline.
./scripts/release.sh <version> [<build>] [<notes>]
Bumps version in build-app.sh, builds, zips, signs the zip with the
Keychain-stored EdDSA private key (auto-downloads sign_update from
the Sparkle 2.9.1 release on first run), prepends a new <item> to
appcast.xml, commits + tags + pushes main, and creates the GitHub
release with the zip uploaded.
- appcast.xml: empty initial feed file at repo root, served via the
raw.githubusercontent.com URL referenced by SUFeedURL. Items are
appended automatically by release.sh.
Public EdDSA key embedded in the build:
iT00+eUw/55obn1suEnWqI7za2pc8mHIFIdRbOWXW1Q=
Private key lives only in the local Keychain on the release machine
(account: macOS login user; service: https://sparkle-project.org).
First-time install still requires the user to remove the quarantine
xattr (no Apple Developer ID); subsequent updates flow through
Sparkle's installer helper and bypass quarantine.
* fix(sparkle): add @executable_path/../Frameworks rpath to OpenLessApp
Without this, the SPM-built executable links Sparkle's symbols but
ships with no rpath that points at the embedded framework, so dyld
fails at launch with:
Library not loaded: @rpath/Sparkle.framework/Versions/B/Sparkle
…and the user sees the macOS Gatekeeper-styled "请与开发者联系,以确保
OpenLess 可以配合此 macOS 版本使用" error. Inject the rpath via
linkerSettings.unsafeFlags so the binary itself knows where to look.
---------
Co-authored-by: baiqing <lbx12309@icloud.com>