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?