fix(mobile): drop the inert app-bound navigation limit from the iOS shell

No WKAppBoundDomains is declared, and an A/B native rebuild showed identical
behavior with and without the flag: the shell's navigation delegate refuses
external navigation either way. The probe script stays as the regression check.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo-H
2026-09-01 23:34:45 -04:00
parent 1e5774022f
commit 75205167a8
3 changed files with 8 additions and 9 deletions
@@ -370,9 +370,8 @@ final class MobileWebShellView: ExpoView, WKNavigationDelegate, WKUIDelegate,
configuration.websiteDataStore = .nonPersistent() configuration.websiteDataStore = .nonPersistent()
configuration.defaultWebpagePreferences.allowsContentJavaScript = true configuration.defaultWebpagePreferences.allowsContentJavaScript = true
configuration.preferences.javaScriptCanOpenWindowsAutomatically = false configuration.preferences.javaScriptCanOpenWindowsAutomatically = false
if #available(iOS 14.0, *) { // Why: no app-bound domain list is declared, so WebKit's app-bound navigation limit would be
configuration.limitsNavigationsToAppBoundDomains = true // inert; the navigation delegate is the fence (hosted-ios-app-bound-navigation-probe).
}
configuration.setURLSchemeHandler(schemeHandler, forURLScheme: mobileWebScheme) configuration.setURLSchemeHandler(schemeHandler, forURLScheme: mobileWebScheme)
messageHandler.target = self messageHandler.target = self
configuration.userContentController.add(messageHandler, name: mobileWebBridgeHandler) configuration.userContentController.add(messageHandler, name: mobileWebBridgeHandler)
@@ -9,11 +9,11 @@ const EXTERNAL_ORIGIN = 'https://example.com/'
const LOG_PREDICATE = const LOG_PREDICATE =
'senderImagePath CONTAINS "WebKit" OR process == "Orca" OR process CONTAINS "com.apple.WebKit"' 'senderImagePath CONTAINS "WebKit" OR process == "Orca" OR process CONTAINS "com.apple.WebKit"'
// The Swift shell sets limitsNavigationsToAppBoundDomains while app.json declares no // The shell once set limitsNavigationsToAppBoundDomains with no WKAppBoundDomains key; an A/B
// WKAppBoundDomains key. The shell's own navigation delegate cancels the same navigations, so the // rebuild showed it inert and the flag was removed. This probe stays as the regression check that
// only way to tell which mechanism fires is to watch who reports the refusal: the delegate raises // the shell's own navigation delegate is what refuses external navigation: the delegate raises
// onNavigationBlocked (a native warning banner), while an app-bound refusal fails the provisional // onNavigationBlocked (a native warning banner), while an app-bound refusal would fail the
// navigation inside WebKit with no delegate decision. // provisional navigation inside WebKit with no delegate decision.
export async function probeHostedIosAppBoundNavigation( export async function probeHostedIosAppBoundNavigation(
{ deviceUdid, emulator, sessionDocument, timeoutMs }, { deviceUdid, emulator, sessionDocument, timeoutMs },
operations = {} operations = {}
@@ -94,7 +94,7 @@ describe('mobile web native bridge transport', () => {
expect(iosSource).toContain('installMobileWebNetworkBlocker(') expect(iosSource).toContain('installMobileWebNetworkBlocker(')
expect(iosSource).toContain('networkBlockReady') expect(iosSource).toContain('networkBlockReady')
expect(iosSource).toContain('networkBlockFailed') expect(iosSource).toContain('networkBlockFailed')
expect(iosSource).toContain('configuration.limitsNavigationsToAppBoundDomains = true') expect(iosSource).not.toContain('limitsNavigationsToAppBoundDomains')
expect(iosSource).toContain('Object.defineProperties(globalThis') expect(iosSource).toContain('Object.defineProperties(globalThis')
expect(iosSource).toContain('var restrictedNavigator=new Proxy(nativeNavigator') expect(iosSource).toContain('var restrictedNavigator=new Proxy(nativeNavigator')
expect(iosSource).toContain("if(property==='serviceWorker') return undefined") expect(iosSource).toContain("if(property==='serviceWorker') return undefined")