r/swift • u/Davidotto13 • 1h ago
Project Building a macOS browser in SwiftUI + WKWebView: what I learned about performance, WebKit profiles and SQLite
For the past few months I've been building Lumen, a native macOS browser written in Swift and SwiftUI on top of WKWebView. I wanted to learn Swift properly, and a browser touches everything: UI, performance, storage and security. It's taught me more than any tutorial.
All the releases are from today because I'd already built the whole browser but never put it on GitHub, so I just uploaded all the versions I'd made. (If you see gaps between the uploads, it's because I was running the tests, building the DMGs and so on.)
Some things I ran into:
- SwiftUI redraws: every tab row was observing the whole browser state, so loading progress on one tab redrew the entire sidebar. Fixed it with
.equatable()rows that take plain values, and by moving fast-changing state (load progress, pull-to-refresh) into separate smallObservableObjects. - Profiles with
WKWebsiteDataStore(forIdentifier:): removing a store while the app is running fails with "in use", and calling it before WebKit has initialised crashed the app. So I erase the data immediately and remove the folder at the next launch. - Resumable downloads:
resumeDownload(fromResumeData:)works well, butdecide(destination:)is not called again on resume, so you have to keep track of the destination yourself. - History moved from JSON to SQLite: I was rewriting a 10k-entry JSON file on every visit. Now it's SQLite in WAL mode with writes on a background serial queue, so one visit is one
INSERT OR REPLACE. - Battery and memory: idle background tabs hibernate in Low Power Mode (
NSProcessInfoPowerStateDidChange) and on memory pressure (DispatchSource.makeMemoryPressureSource). - Self-updating without Sparkle: it downloads from GitHub Releases and checks the file with a SHA256 (CryptoKit) and
codesign --verify --deep --strictbefore replacing itself.
Tech: Swift, SwiftUI, WKWebView, SQLite. No Electron, no third-party dependencies.
It's completely free and open source.
Download it from: scadavide55.github.io/Lumen
Code: github.com/scadavide55/Lumen
It's still a work in progress (latest pre-release is 1.5.2), so code review and criticism are very welcome. What would you have done differently?


