On the open web, tapping a Universal Link hands the OS a chance to open your app; an App Link on Android does the same. Inside a WebView, that handoff dies. When a WebView loads a URL itself, the operating system is never asked which app should handle it, so the association files your app published are never consulted. For a fintech app, that means the redirect that should push the user into their bank's app for 3DS / SCA strong-customer-authentication, or into a wallet app to confirm a payment, silently lands back on a web page — or nowhere. A host-owned runtime bridges native app-opening so the handoff works on every engine.
Universal Links never fire inside a WebView
Universal Links and Android App Links are an OS-level mechanism. When a user taps a link in Safari, Chrome, or the system browser, iOS or Android checks the domain's apple-app-site-association / assetlinks.json and, if a matching app is installed, opens it. The interception happens before any browser renders the page. But when a WebView loads that same URL, the host app already has a web view open and simply renders the URL inside it. The OS is never consulted, so the association file is irrelevant and the app never launches. Apple documents this directly: instantiating a WKWebView to handle a Universal Link causes iOS to open the website in Safari instead of your app; the link only opens the app if the user taps it from within an already-embedded view — and even then the host must act. JavaScript redirects (window.location.href) are specifically not counted as user-initiated navigation, so they are ignored by the OS resolver too.
Custom URI schemes are suppressed too
The older escape hatch — a custom URI scheme like myapp:// — is also unreliable inside WebView. On iOS there is no supported way for a page inside a WKWebView to force the host app to hand off; a custom scheme is suppressed in most webview contexts and fails silently with no fallback. On Android, a raw WebView does not resolve App Links either; only Android Custom Tabs (a genuine browser instance) do. A host can override shouldOverrideUrlLoading on Android or implement decidePolicyFor navigationAction on iOS to call UIApplication.open, but most apps — especially social and super-apps that wrap third-party content — do not, because keeping the user inside the web view is the point. The result is the same everywhere: the cross-app jump the page depends on does not happen.
What breaks when the handoff dies
- 3DS / SCA redirect to the bank app fails. Strong customer authentication often hands off to the issuing bank's app. Inside a WebView that hop is swallowed, so the authentication stalls or silently returns to a web fallback the bank never finished.
- Wallet and payment confirmation breaks. "Confirm in your wallet app" links that should deep-link into Google Pay, Apple Pay, or a banking app instead do nothing.
- Account-linking and OAuth callbacks misfire. "Open the authenticator / banking app to approve" flows land on a blank or dead-end page.
- Attribution and install handoffs are lost. Deferred deep links that should survive an install and land the user on the right screen break, hurting activation funnels.
The runtime fix
A host-owned runtime owns the cross-app handoff. The page calls one uniform API — runtime.openApp(url) — and the host resolves it through the platform-native mechanism: UIApplication.open on iOS (with the Universal Link or a scheme the host vets) and an Android Intent / App Link on Android, with a web fallback when no app is installed. The runtime can also detect that it is inside an embedded view and surface an explicit "Open in browser" affordance, instead of a link that appears to do nothing. One integration, every engine, a real handoff at the end of it.
| Dimension | WebView | Host-owned runtime |
|---|---|---|
| OS link resolution | Never consulted | Host calls native open |
| Universal / App Links | Swallowed | Honored via native open |
| Custom URI scheme | Suppressed / silent fail | Vetted host handoff |
| iOS escape hatch | None reliably | UIApplication.open |
| Android escape hatch | Only Custom Tabs | Intent / App Link |
| 3DS / wallet handoff | Breaks | Works |
| Fallback when no app | None | Explicit web fallback |
A native app can open another app on every device. A stock WebView can on almost none. A runtime gives the page one call — and a handoff that actually lands.
Sources
- Apple Developer — Supporting Universal Links — instantiating a WKWebView to handle a Universal Link opens the website in Safari instead of the app; the OS resolver is bypassed.
- Apple Developer — UIApplication.open — the native API a host must call to route a URL out of the WebView to another app.
- Deeplinkly — Deep links in in-app browsers — a WebView loads the URL itself so the OS is never asked to resolve it; Universal Links and App Links never reach the claiming app.
- LinkRunner — Universal Links and App Links break in in-app browsers — WKWebView does not trigger Universal Link interception; JavaScript redirects are not user-initiated and are ignored.
- Tolinku — URI Schemes vs Universal Links — inside your app (WKWebView / SFSafariViewController) Universal Links are disabled by default; you must open via
UIApplication.shared.open().