Error Domain=WebKitErrorDomain Code=102 "Frame load interrupted" iOS WKwebview WKnavigationdelegate

1.5k views Asked by At

I´m working on an app that will show a website. But I'm running into errors when loading the website in app. I´ts also working perfectly fine on android.

The error:

WebPageProxy::didFailProvisionalLoadForFrame: frameID = 3, domain = WebKitErrorDomain, code = 102 Error Domain=WebKitErrorDomain Code=102 "Frame load interrupted" UserInfo={_WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x600001922120>, NSErrorFailingURLStringKey=https://site.site/login, NSErrorFailingURLKey=https://site.site/login, NSLocalizedDescription=Frame load interrupted} Failed Provisinal Navigation

My code:

//  ViewController.swift
import UIKit
import WebKit
import SafariServices
import PushNotifications

class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {

    let pushNotifications = PushNotifications.shared
    var webView: WKWebView!
    var manifest = WebAppManifest.shared

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){

        if let objStr = message.body as? String {

            var arr = [" "," "]

            if objStr.contains(";") {

                arr = objStr.components(separatedBy: ";")

            }

            let tokenProvider = BeamsTokenProvider(authURL: "https://site.site/beams/token") { () -> (AuthData) in

                let headers : [String: String] = [:]

                var queryParams : [String: String] = [:]

                if objStr.contains(";") {

                    queryParams = ["api_token":arr[1]]

                }

                return AuthData(headers: headers, queryParams: queryParams)

            }

            

            if objStr.contains(";") {

                self.pushNotifications.setUserId(arr[0], tokenProvider: tokenProvider, completion: { error in

                    guard error == nil else {

                        print(error.debugDescription)

                        return

                    }

                    print("Succesfully authenticated with Pusher Beams")

                })

            } else {

                self.pushNotifications.setUserId(objStr, tokenProvider: tokenProvider, completion: { error in

                    guard error == nil else {

                        print(error.debugDescription)

                        return

                    }

                    print("Succesfully authenticated with Pusher Beams")

                })

            }

        }

    }

    override func viewDidLoad() {

        super.viewDidLoad()

        let contentcontroller = WKUserContentController()

        contentcontroller.add(self, name: "callbackHandler")

        let config = WKWebViewConfiguration()

        config.userContentController = contentcontroller

        // Set-up the UI

        self.view.backgroundColor = UIColor(fromHex: manifest.theme_color)

        // Creates the web view engine

        webView = WKWebView()

        view.addSubview(webView)

        webView.navigationDelegate = self

        // Display attribute

        var guide: AnyObject = self.view.safeAreaLayoutGuide

        if manifest.display == "fullscreen" {

            guide = self.view

            webView.scrollView.contentInsetAdjustmentBehavior = .always

        }

        // Make the Web View take the whole screen

        webView.translatesAutoresizingMaskIntoConstraints = false

        webView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true

        webView.rightAnchor.constraint(equalTo: guide.rightAnchor).isActive = true

        webView.leftAnchor.constraint(equalTo: guide.leftAnchor).isActive = true

        webView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true

        // It will enable navigation gestures on the web view

        webView.allowsBackForwardNavigationGestures = true

        let url = URL(string: "https://" + manifest.origin + manifest.start_url)!

        print(pushNotifications.getDeviceInterests())

        webView.load(URLRequest(url: url))

    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {

        get {

            switch manifest.orientation {

            case "landscape":

                return UIInterfaceOrientationMask.landscape

            case "portrait":

                return UIInterfaceOrientationMask.portrait

            default:

                return UIInterfaceOrientationMask.all

            }

        }

        set { self.supportedInterfaceOrientations = newValue }

    }

    override var prefersStatusBarHidden: Bool {

        return manifest.display == "fullscreen"

    }

    override var preferredStatusBarStyle: UIStatusBarStyle {

        return UIColor(fromHex: manifest.theme_color).isDark() ? .lightContent : .darkContent

    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        view.setNeedsLayout()

    }

    // MARK: loadWebPage function

    func loadWebPage(url: URL)  {

        var components = URLComponents(url: url, resolvingAgainstBaseURL: false)

    components?.query = nil

        // If already has a query then append a param

        // otherwise create a new one

        if let query = url.query {

            // If isFromMobile param already exists jsut reassign the existing query

            if query.contains("source=TWA&platform=iOS") {

                components?.query = query

            } else {

                 components?.query = query + "&source=TWA&platform=iOS"

            }

        } else {

            components?.query = "source=TWA&platform=iOS"

        }

        print(components!.url!)

        let customRequest = URLRequest(url: components!.url!)

        webView!.load(customRequest)

    }

    // MARK: NavigationAction handler

    // Defines if it should navigate to a new URL

    // Logic to check if the destination URL is in the scope

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

        print(navigationAction.request.url?.absoluteURL)

        if let host = navigationAction.request.url?.host,

           let path = navigationAction.request.url?.path{

            if host.contains(manifest.origin) &&

                path.starts(with: manifest.scope){

                let query = navigationAction.request.url?.query

                if  query != nil{

                    print("two")

                    // MARK: Pusher clear state

                    if path.contains("logout") || path.contains("login") {

                        pushNotifications.clearAllState {

                            print("Cleared all state!")

                        }

                    }

                    decisionHandler(.allow)

                } else {

                    print("one")

                    loadWebPage(url: navigationAction.request.url!)

                    decisionHandler(.cancel)

                }

                return

            } else {

                print("wrong")

                // Destination URL is out of the scope

                if navigationAction.request.url?.scheme == "http" ||

                    navigationAction.request.url?.scheme == "https" {

                    // Opens an In-App browser

                    decisionHandler(.cancel)

                    let safariVC = SFSafariViewController(url: navigationAction.request.url!)

                    safariVC.preferredBarTintColor = UIColor(fromHex: manifest.theme_color)

                    safariVC.preferredControlTintColor =

                        UIColor(fromHex: manifest.theme_color).isDark() ? UIColor.white : UIColor.black

                    present(safariVC, animated: true)

                } else {

                    // It looks like a different protocol

                    // We ask the OS to open it

                    UIApplication.shared.open(navigationAction.request.url!)

                }

            }

        } else {

            decisionHandler(.cancel)

        }

    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,

                 decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {

        print("error")

        if let response = navigationResponse.response as? HTTPURLResponse {

            if response.statusCode >= 400 {

                print("400 error")

                handleError()

            }

        }

        decisionHandler(.allow)

    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {

        print(error, "Failed Navigation")

        handleError()

    }

    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {

        print(error, "Failed Provisinal Navigation")

        handleError()

    }

    // Error handling in case the content of the PWA can't be loaded

    func handleError() {

        webView.loadHTMLString("<h1>:(</h1>", baseURL: nil)

        let alert = UIAlertController(title: "Error", message: "There was a problem loading the App from the Internet. Please check your connection and try again", preferredStyle: .alert)

        alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: { (action) in

            exit(100)

        }))

        present(alert, animated: true)

    }

}

I have already made multiple apps of this type of but never had this error pop up. Any suggestion on how to fix this?

0

There are 0 answers