feature(updater): Implement auto-updating system using AppCast protocol
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# Launcher Self-Update
|
||||
|
||||
MoonWell Launcher uses `auto_updater` 1.0.0, backed by WinSparkle 0.8.1, to
|
||||
update installed Windows launchers from an AppCast feed. This is independent of
|
||||
the manifest-based World of Warcraft client synchronization.
|
||||
|
||||
The launcher performs one background update check after its window is visible.
|
||||
WinSparkle shows its native prompt only when a newer version is available.
|
||||
Missing configuration, network failures, and malformed feeds do not block the
|
||||
launcher. Periodic WinSparkle checks are disabled.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
Pass the public feed URL at build time:
|
||||
|
||||
```powershell
|
||||
flutter build windows `
|
||||
--dart-define=MOONWELL_API_BASE_URL=https://host `
|
||||
--dart-define=MOONWELL_APPCAST_URL=https://host/launcher/updates/appcast.xml
|
||||
```
|
||||
|
||||
The feed URL must be an absolute HTTPS URL. Omit
|
||||
`MOONWELL_APPCAST_URL` to disable self-update, including for ordinary local
|
||||
development.
|
||||
|
||||
## Signing Keys
|
||||
|
||||
WinSparkle verifies installer artifacts with a DSA signature. The public key is
|
||||
committed at `windows/runner/resources/dsa_pub.pem` and embedded as the
|
||||
`DSAPub` resource. The corresponding private key is local signing material at
|
||||
`.moonwell_signing/dsa_priv.pem`; it is ignored by Git and must be backed up to
|
||||
the project secret store before publishing the first update.
|
||||
|
||||
Never commit or upload the private key. Losing it prevents existing
|
||||
installations from accepting future updates. Rotating it requires shipping an
|
||||
ordinary installer containing the replacement public key before publishing
|
||||
artifacts signed by the replacement private key.
|
||||
|
||||
The AppCast signature is not Authenticode. Publicly trusted Authenticode
|
||||
certificates and managed signing services are paid products, so MoonWell does
|
||||
not currently Authenticode-sign the installer. Windows can therefore display
|
||||
an unknown-publisher or SmartScreen warning. A free self-signed Authenticode
|
||||
certificate would not establish trust on player machines.
|
||||
|
||||
## Version and AppCast Contract
|
||||
|
||||
Increase the `X.Y.Z` version in `pubspec.yaml` for every launcher release. A
|
||||
build-number-only change such as `1.0.0+2` is not sufficient because WinSparkle
|
||||
compares the Windows product version. Pass the same `X.Y.Z` value to Inno Setup:
|
||||
|
||||
```powershell
|
||||
ISCC.exe /DMyAppVersion=1.1.0 installer\moonwell_launcher.iss
|
||||
```
|
||||
|
||||
The resulting artifact is
|
||||
`build/installer/moonwell_launcher_1.1.0_windows_setup.exe`.
|
||||
|
||||
Use a public AppCast with absolute URLs:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0"
|
||||
xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||
<channel>
|
||||
<title>MoonWell Launcher</title>
|
||||
<description>MoonWell Launcher updates</description>
|
||||
<language>ru</language>
|
||||
<item>
|
||||
<title>MoonWell Launcher 1.1.0</title>
|
||||
<sparkle:releaseNotesLink>https://host/launcher/updates/1.1.0/release-notes.html</sparkle:releaseNotesLink>
|
||||
<pubDate>Sun, 21 Jun 2026 12:00:00 +0400</pubDate>
|
||||
<enclosure
|
||||
url="https://host/launcher/updates/1.1.0/moonwell_launcher_1.1.0_windows_setup.exe"
|
||||
sparkle:version="1.1.0"
|
||||
sparkle:os="windows"
|
||||
sparkle:dsaSignature="SIGNATURE_FROM_SIGN_UPDATE"
|
||||
length="ACTUAL_INSTALLER_SIZE_IN_BYTES"
|
||||
type="application/octet-stream" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
```
|
||||
|
||||
The installer URL and release-notes URL must be absolute. The publication host
|
||||
must serve the feed, notes, and installer without authentication or redirects
|
||||
to an authenticated endpoint.
|
||||
|
||||
## Manual Release
|
||||
|
||||
Perform Windows signing on the Windows release machine because the package
|
||||
invokes WinSparkle's Windows signing utility.
|
||||
|
||||
1. Update `pubspec.yaml` to the new `X.Y.Z+N` version.
|
||||
2. Run `flutter pub get`, formatting, analysis, and all tests.
|
||||
3. Build Windows with both production `--dart-define` values.
|
||||
4. Compile the installer with `ISCC.exe /DMyAppVersion=X.Y.Z`.
|
||||
5. Make the private key available outside the repository and sign the artifact:
|
||||
|
||||
```powershell
|
||||
dart run auto_updater:sign_update `
|
||||
build\installer\moonwell_launcher_X.Y.Z_windows_setup.exe `
|
||||
C:\secure-path\dsa_priv.pem
|
||||
```
|
||||
|
||||
6. Copy the emitted `sparkle:dsaSignature` into the enclosure. The package's
|
||||
Windows helper reports `length="0"`; replace it with the actual value from:
|
||||
|
||||
```powershell
|
||||
(Get-Item build\installer\moonwell_launcher_X.Y.Z_windows_setup.exe).Length
|
||||
```
|
||||
|
||||
7. Upload the versioned installer and release notes first.
|
||||
8. Download the hosted installer, verify its byte length, and test its DSA
|
||||
signature before changing the feed.
|
||||
9. Publish `appcast.xml` last so clients never observe an incomplete release.
|
||||
|
||||
Keep the preceding installer available for rollback and support. Rollback is a
|
||||
new release with a product version higher than the faulty release; WinSparkle
|
||||
does not install a lower version as an update.
|
||||
|
||||
## Release Verification
|
||||
|
||||
Test from an installed older version on a clean Windows x64 machine:
|
||||
|
||||
- offline or invalid feed: launcher remains usable and writes a log entry
|
||||
- same or older feed version: no update prompt
|
||||
- valid newer release: prompt, download, launcher exit, install, and relaunch
|
||||
- modified installer or invalid DSA signature: WinSparkle rejects the update
|
||||
- launcher session and selected game directory remain after installation
|
||||
|
||||
Watch the debug output for Flutter platform-channel thread warnings during the
|
||||
test. `auto_updater` has an open Windows callback-thread issue; do not release
|
||||
if it reproduces. Patch and pin `auto_updater_windows` so native callbacks are
|
||||
marshalled onto Flutter's platform thread, then repeat the complete update test.
|
||||
Reference in New Issue
Block a user