feat: add deepLinkHosts prop to escape known external URLs#241
Open
allen-paystack wants to merge 2 commits into
Open
feat: add deepLinkHosts prop to escape known external URLs#241allen-paystack wants to merge 2 commits into
allen-paystack wants to merge 2 commits into
Conversation
Adds an opt-in prop to PaystackProvider that intercepts specific WebView navigations and hands them to the OS via Linking.openURL. This is needed because WKWebView on iOS does not perform universal-link handoff or custom-scheme dispatch for navigations originated inside the WebView. Integrators using partner deep links (e.g. universal links pointing to a partner app) currently see those links load as web pages inside the checkout, instead of opening the target app. Default is an empty array, so behavior is unchanged for existing users. Allowlist entries can be RegExp or string-prefix matchers. Paystack hosts, 3DS ACS hosts, and other checkout-flow URLs are intentionally NOT matched by default — those must stay in the WebView.
Make the deep-link interceptor opinionated: every consumer of the library gets universal-link handoff to the Zap app out of the box, without needing to pass deepLinkHosts explicitly. Exports DEFAULT_DEEP_LINK_HOSTS so integrators can extend, override, or disable the curated list (pass [] to turn off interception). The list is intentionally narrow — currently joinzap.com only — to avoid escaping URLs that the checkout flow needs to load in-WebView (3DS ACS challenge pages, issuer redirects, Paystack hosts).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opinionated
deepLinkHostsprop toPaystackProvider. The provider now intercepts navigations to a curated list of partner deep-link hosts and forwards them to the OS viaLinking.openURL, so they trigger iOS universal-link handoff (or custom-scheme dispatch) instead of loading as a web page inside the checkout WebView.The default ships with
joinzap.comalready in the list, so every consumer of the library gets the fix without needing to opt in. Integrators can extend, replace, or disable the list via thedeepLinkHostsprop.Why
On iOS, WKWebView does not perform universal-link handoff or custom-scheme dispatch for navigations originated inside the WebView. The only entry points that do are
UIApplication.open(_:)(whichLinking.openURLcalls under the hood), Safari, Mail, Messages, andSFSafariViewController.Practical consequence: when checkout is opened in
react-native-paystack-webviewand a payment channel needs to hand off to a partner app — for example the Zap channel, which renders a universal link tohttps://joinzap.com/...— tapping the link inside the WebView currently loads the URL as a regular web page instead of opening the Zap app. Confirmed on a physical iPhone running iOS 26.x.This is widely-known WebView behavior (Apple Developer Forums, WWDC 2015 Session 509). The canonical workaround is host-side: intercept the navigation and call
UIApplication.open(_:).What changed
PaystackProvidernow accepts adeepLinkHosts?: Array<string | RegExp>prop.Linking.openURL(url).RegExpentries use.test(url); string entries match if the URL starts with the string.DEFAULT_DEEP_LINK_HOSTSconstant is exported, currently containingjoinzap.com(and subdomains). It's the prop's default value.Examples
Out of the box, no integrator action needed:
Extend the default list with your own partner deep links:
Disable interception entirely:
Verified
onShouldStartLoadWithRequestworks equivalently on both platforms inreact-native-webview, andLinking.openURLroutes throughIntent.ACTION_VIEWon Android, which respects App Links.)yarn test, 8/8).yarn build).Backwards compatibility
This is the one place the patch changes default behavior: navigations to
joinzap.com(and any subdomain) that were previously loaded inside the WebView will now open via the OS. That's the intended fix — those navigations were already broken in practice (WKWebView refuses to do universal-link handoff for them). Any integrator that needs to preserve the previous in-WebView behavior can passdeepLinkHosts={[]}.Notes for reviewers