Overview
AppUpdater handles the complete update installation workflow: downloading DMG files from GitHub releases, mounting the DMG, copying the new app version, and replacing the running app. It provides observable state for UI progress tracking and implements safety checks to prevent installation errors.
Located at:
Fiaxe/Services/AppUpdater.swift:9Update WorkflowThe updater works in conjunction with UpdateService which fetches release metadata from GitHub. AppUpdater handles the actual download and installation.
Type Definition
Singleton Instance
State Management
The updater tracks installation progress through an observable state enum:State
No update operation in progress.
State
Downloading DMG from GitHub. Associated value is progress (0.0 to 1.0).
State
DMG downloaded and cached, ready to install. Contains local DMG URL.
State
Installing update (mounting DMG, copying files, replacing app).
State
Update failed. Associated value contains error message.
@Observable macro makes state changes automatically update SwiftUI views.
Methods
install()
Starts the update installation process.GitHubRelease
required
GitHub release to install. Must contain a DMG asset.
download(release:).
download()
Downloads the DMG file from the release.GitHubRelease
required
Release containing the DMG download URL.
Implementation Details
- Extracts DMG URL from release assets
- Sets state to
.downloading(0) - Creates a URLSession with self as delegate for progress tracking
- Starts the download task
cancel()
Cancels an in-progress download..idle and cancels the download task.
installDownloaded()
Installs a previously downloaded DMG..downloaded(URL). Calls mountAndInstall(dmg:) internally.
Update Capability Checks
canSelfUpdate
Whether the app can update itself in place.updateBlockReason
Reason why self-update is blocked, ornil if allowed.
Implementation Details
- Running from Xcode build (
/DerivedData/or/Build/Products/) - App isn’t in a writable location (e.g., inside a mounted DMG)
URLSessionDownloadDelegate
The updater implementsURLSessionDownloadDelegate for progress tracking.
Progress Updates
Download Completion
Installation Process
ThemountAndInstall(dmg:) method handles the complex installation workflow:
1
Mount DMG
Uses Parses plist output to find mount point (e.g.,
hdiutil attach to mount the DMG and parse the mount point:/Volumes/R2Vault).2
Find .app Bundle
Searches mounted volume for the .app bundle:
3
Copy to Temp Location
Copies the new app to temp to avoid modifying the running app:
4
Unmount DMG
Detaches the DMG after copying:
5
Schedule Post-Quit Replacement
Launches a background shell script that:
- Waits for the current app to quit
- Replaces the old app with the new one
- Removes quarantine attributes
- Relaunches the app
6
Quit App
Terminates the running app:
Error Handling
UpdateError
Couldn’t find a .app bundle inside the mounted DMG.
UpdateError
Failed to determine the running app’s file path.
UpdateError
hdiutil attach failed or didn’t return a mount point.UpdateError
A shell command exited with non-zero status. Includes command, exit code, and stderr.
UpdateError
A command exceeded its timeout duration.
UpdateError
The app’s location isn’t writable (e.g., inside a read-only DMG).
Logging
The updater logs all operations to a file:Usage Example
Security Considerations
App Store Distribution
If distributing via the Mac App Store:
- Remove the auto-update system entirely
- App Store handles all updates automatically
- Self-updating violates App Store guidelines
- Can still check GitHub API to notify users
Related Services
- UpdateService - Fetches release metadata from GitHub
- MenuBarManager - Can display update notifications