Bug Description
With a remote devServerURL, any failed or cancelled main-frame load makes the iOS shell load the bundled copy (craft://app/index.html), and it stays there for the rest of the process's life.
didFailProvisionalNavigation and didFail both call loadBundledFallback(in:) without looking at the error (packages/ios/templates/CraftApp.swift:1455-1468 at v0.0.92), and loadedBundledFallback only ever goes one way.
Two consequences:
- A cancelled load is not a failure. WebKit reports
NSURLErrorCancelled(-999) whenever a new navigation starts before the previous one commits: two quick taps, alocation.assignwhile a load is in flight, a redirect. Each of those currently ends the session on the bundled copy. - The bundled copy cannot reach the app's API. It is served from
craft://app, so a frontend that calls its API by relative path (fetch('/api/…')) has no API until the app is killed and relaunched. In WildLoop it also showed a stale landing page, since the bundle is whatever web build was last copied in.
Steps to Reproduce
- Generate an iOS app whose
devServerURLis a remote or dev-server URL. - From a page, start two main-frame navigations in quick succession against a server slow enough that the first has not committed, e.g.
location.assign('/a'); setTimeout(() => location.assign('/b'), 50). - The first provisional navigation fails with -999;
loadBundledFallbackruns and the WebView loadscraft://app/index.html. - Every later navigation stays on
craft://app.
Seen in WildLoop after quick tab taps on a slow dev server. The path above is read from the template; I have not written an automated repro.
Expected Behavior
- Cancellations are ignored:
NSURLErrorCancelled, and WebKit's frame-load-interrupted error (WebKitErrorDomain102). - The bundled copy is used only for connectivity failures, e.g. not connected, cannot find or connect to host, timed out, connection lost.
- Once on the bundled copy, the app goes back to the remote URL when connectivity returns (a path monitor) or on the next foreground, rather than staying there until the process dies.
Actual Behavior
Any error, -999 included, switches the WebView to the bundled copy for the rest of the process.
Platform
iOS (Simulator, iPhone 17 Pro)
OS Version
iOS 26.5
Craft Version
craft-native 0.0.92 (template at 186cd83)