Feature to implement: Cards payment integration using Paysafe provider. The user shall be able to fill their card details in textFields, which are generated in an HTML file provided by Paysafe.
Implementation: There is a WebViewController that loads an HTML file with this js: https://hosted.paysafe.com/js/v1/latest/paysafe.min.js This is how it looks like: Paysafe Payment Form
Problem: After submitting the payment, a 3DS secure authentication pop-up should appear in order to enter a 4-digit code sent by SMS. Only after this verification succeeds, the payment is going through. The pop-up window in the WebViewController does not appear neither on the simulator nor on a real device.
I have tried different advice to make the pop-up window appear, but nothing is working. Here is the WebViewController:
import UIKit
import WebKit
class WebViewController: UIViewController, UIWebViewDelegate {
@IBOutlet weak var webViewContainer: UIView!
@IBOutlet weak var navItem: UINavigationItem!
var webView: WKWebView!
var urlToLoad = ""
var htmlToLoad = ""
let loadingIndicatorSize = CGFloat(37)
var loadingIndicator: UIActivityIndicatorView
private var popupWebView: WKWebView?
required init?(coder aDecoder: NSCoder) {
let loadingIndicatorFrame = CGRect(
x: screenSize.width / 2,
y: screenSize.height / 2 - loadingIndicatorSize * 2,
width: loadingIndicatorSize,
height: loadingIndicatorSize
)
loadingIndicator = UIActivityIndicatorView(frame: loadingIndicatorFrame) as UIActivityIndicatorView
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
navItem.leftBarButtonItem = UIBarButtonItem(title: L("Done"), style: .done, target: self, action: #selector(done))
navItem.leftBarButtonItem?.tintColor = Colors.brand
initWebView()
setupNavigationItem(Colors.background)
}
override func viewDidAppear(_ animated: Bool) {
if !urlToLoad.isEmpty {
loadUrl()
} else if !htmlToLoad.isEmpty {
loadHtml()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@objc func done() {
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
}
func initWebView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
webView.allowsLinkPreview = true
webView.configuration.defaultWebpagePreferences.allowsContentJavaScript = true
webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webViewContainer.addSubview(webView)
webViewContainer.sendSubviewToBack(webView)
common.addConstraints(to: webView, with: webViewContainer)
}
func loadUrl() {
if let url = URL(string: urlToLoad) {
let request = URLRequest(url: url)
DispatchQueue.main.async { [weak self] in
self?.webView.load(request)
self?.webView.allowsBackForwardNavigationGestures = true
self?.view.setNeedsLayout()
}
} else {
showAlertMessageOk(title: L("ERROR"), message: L("URL is wrong"))
}
}
func loadHtml() {
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return }
self?.webView.loadHTMLString(strongSelf.htmlToLoad, baseURL: nil)
self?.webView.allowsBackForwardNavigationGestures = true
self?.view.setNeedsLayout()
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
startLoadingAnimation()
}
override func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
stopLoadingAnimation()
// let script = """
// var elements = document.getElementsByTagName("*")
// for (var i = 0; i < elements.length; i++) {
// if (elements[i].target == '_blank') {
// elements[i].target = '_self'
// }
// }
// """
// webView.evaluateJavaScript(script, completionHandler: nil)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
stopLoadingAnimation()
showAlertMessageOk(title: L("Failed"), message: L("CannotLoadPage"))
}
//MARK: - Handling links containing untrusted certificates.
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
DispatchQueue.global(qos: .userInteractive).async {
let exceptions = SecTrustCopyExceptions(serverTrust)
SecTrustSetExceptions(serverTrust, exceptions)
completionHandler(.useCredential, URLCredential(trust: serverTrust))
}
}
func startLoadingAnimation() {
webView.addSubview(loadingIndicator)
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = .medium
loadingIndicator.startAnimating()
}
func stopLoadingAnimation() {
loadingIndicator.stopAnimating()
loadingIndicator.removeFromSuperview()
}
func webView(
_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures
) -> WKWebView? {
// popupWebView = WKWebView(frame: view.bounds, configuration: configuration)
// popupWebView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// popupWebView?.navigationDelegate = self
// popupWebView?.uiDelegate = self
// if let newWebview = popupWebView {
// view.addSubview(newWebview)
// }
// return popupWebView ?? nil
self.webView?.load(navigationAction.request)
return nil
// if navigationAction.targetFrame == nil {
// let webViewtemp = WKWebView(
// frame: view.bounds,
// configuration: configuration
// )
// webViewtemp.navigationDelegate = self
// webView.superview?.addSubview(webViewtemp)
// //view.addSubview(webViewtemp)
// //containerStack.addArrangedSubview(webViewtemp)
// return webViewtemp
// } else {
// webView.load(navigationAction.request)
// return webView
// }
}
func webViewDidClose(_ webView: WKWebView) {
webView.removeFromSuperview()
}
}