11import WebKit
22
3- class CheckoutViewController : UIViewController , WKNavigationDelegate {
4-
3+ class CheckoutViewController : UIViewController , WKNavigationDelegate , WKUIDelegate {
4+
5+ // Prefix, not substring - otherwise a page could smuggle the host into a
6+ // query string (e.g. https://evil.com/?u=https://joinzap.com/app/) and
7+ // force an external open.
8+ private let deepLinkPrefixes = [ " https://joinzap.com/app/ " ]
9+
510 // ..........
6-
7- //This is helper to get url params
11+
12+ //This is helper to get url params
813 func getQueryStringParameter( url: String , param: String ) -> String ? {
914 guard let url = URLComponents ( string: url) else { return nil }
1015 return url. queryItems? . first ( where: { $0. name == param } ) ? . value
1116 }
12-
17+
1318 // This is a WKNavigationDelegate func we can use to handle redirection
14- func webView( _ webView: WKWebView , decidePolicyFor navigationAction: WKNavigationAction ,
15- decisionHandler: @escaping ( ( WKNavigationActionPolicy ) -> Void ) {
19+ func webView( _ webView: WKWebView , decidePolicyFor navigationAction: WKNavigationAction ,
20+ decisionHandler: @escaping ( WKNavigationActionPolicy ) -> Void ) {
1621
1722 if let url = navigationAction. request. url {
18-
23+
24+ // Partner-app handoff: cancel the load and ask the OS to open it.
25+ // `universalLinksOnly: true` means open the app, or fail - never fall
26+ // back to loading the page in Safari.
27+ if deepLinkPrefixes. contains ( where: { url. absoluteString. hasPrefix ( $0) } ) {
28+ UIApplication . shared. open ( url, options: [ . universalLinksOnly: true ] ) { opened in
29+ if !opened {
30+ UIApplication . shared. open ( url) // app not installed; web fallback
31+ }
32+ }
33+ decisionHandler ( . cancel)
34+ return
35+ }
36+
1937 /*
2038 We control here when the user wants to cancel a payment.
21- By default a cancel action redirects to http://cancelurl.com/.
22- Based on our workflow we can for example remove the webview or push
23- another view to the user.
39+ By default a cancel action redirects to http://cancelurl.com/.
40+ Based on our workflow we can for example remove the webview or push
41+ another view to the user.
2442 */
2543 if url. absoluteString == " http://cancelurl.com/ " {
2644 decisionHandler ( . cancel)
2745 }
2846 else {
2947 decisionHandler ( . allow)
3048 }
31-
32- //After a successful transaction we can check if the current url is the callback url
33- //and do what makes sense for our workflow. We can get the transaction reference for example.
49+
50+ //After a successful transaction we can check if the current url is the callback url
51+ //and do what makes sense for our workflow. We can get the transaction reference for example.
3452
3553 if url. absoluteString. hasPrefix ( callbackUrl) {
3654 let reference = getQueryStringParameter ( url: url. absoluteString, param: " reference " )
3755 print ( " reference \( reference) " )
3856 }
3957 }
4058 }
41- }
59+
60+ // A link with target="_blank" produces no navigation action in the main
61+ // frame, so without this WKUIDelegate method the tap is silently dropped.
62+ // Requires `webView.uiDelegate = self` to be set where the WebView is created.
63+ func webView( _ webView: WKWebView , createWebViewWith configuration: WKWebViewConfiguration ,
64+ for navigationAction: WKNavigationAction , windowFeatures: WKWindowFeatures ) -> WKWebView ? {
65+ if navigationAction. targetFrame == nil {
66+ webView. load ( navigationAction. request)
67+ }
68+ return nil
69+ }
70+ }
0 commit comments