iOS and macOS app with a WKWebView that loads local resources, based on one of my SO answers.
file:// |
app:// |
|---|---|
![]() |
![]() |
- Local HTML, CSS and JS files shipped in the app bundle (
web/) - Remote HTML, CSS and JS files (as requested by edon2005):
- downloading
custom_css_js.zipwithURLSessionand unzipping it with ZIPFoundation - loading the unzipped files from Application Support in the WKWebView
- downloading
- Two ways of loading those files, switchable in the app:
file://–loadFileURL(_:allowingReadAccessTo:). Simplest option. The page has anullorigin though, sofetch(), XHR and ES modules don't work.app://– aWKURLSchemeHandlerserves the same files underapp://local/. The page gets a real origin and behaves like it's on a web server. The bundled page fetchesdata.jsonto show the difference.
- Safari Web Inspector (Develop menu) in debug builds
- Xcode 26
- iOS 17+ / macOS 14+
- Clone project
- Open
LocalWKWebView/LocalWKWebView.xcodeproj(Xcode fetches ZIPFoundation via Swift Package Manager) - Pick your own team under Signing & Capabilities if you want to run on a device
- Run on iOS or macOS and use the two segmented controls to switch between bundled/downloaded files and
file:///app://
WebView.swift– WKWebView wrapper for SwiftUI and the two loading methodsLocalSchemeHandler.swift– theapp://scheme handlerRemoteContent.swift– downloading and unzipping the remote files
On iOS 26 / macOS 26 and later SwiftUI has its own WebView and WebPage with support for custom URL schemes, so the wrapper isn't needed there.

