how to Add timeout for WKWebview - ios

How to write a timeout handler for WKWebView, when default delegates are not getting called for didFailNavigation.
WKWebView delegate are set & DidFinishNavigation or didFailProvisionalNavigation is getting called.

Use the error.code value of the error that didFailProvisionalNavigation creates and add your 'handler' code there:
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
if error.code == -1001 { // TIMED OUT:
// CODE to handle TIMEOUT
} else if error.code == -1003 { // SERVER CANNOT BE FOUND
// CODE to handle SERVER not found
} else if error.code == -1100 { // URL NOT FOUND ON SERVER
// CODE to handle URL not found
}
}

Use this delegate method
webView:didFailProvisionalNavigation:withError:
Document
Invoked when an error occurs while starting to load data for the main frame.
And check the error code
NSURLErrorTimedOut = -1001
All the error code list

One possible solution is to add custom timer, which starts as you call loadHTML, loadRequest methods and times out on custom interval

Compared to Timer , asyncAfter(deadline:) is more light-weighted.
var isTimeOut = true
DispatchQueue.main.asyncAfter(deadline: .now() + timeOut) {
if isTimeOut{
// do time out thing
}
}
check isTimeOut according to WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!){
isTimeOut = false
}

Related

WKWebView: [ProcessSuspension] - TimedActivity::activityTimedOut:

I'm using a WKWebView to load a page, but after might be 5 minutes I got:
[ProcessSuspension] 0x7fded682fec8 - TimedActivity::activityTimedOut:
2021-07-06 15:20:32.751176+0800 ATP Demo2[15923:9181871] [ProcessSuspension] 0x7fded68dd6c8 - TimedActivity::activityTimedOut:
2021-07-06 15:20:33.020953+0800 ATP Demo2[15923:9181871] Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
These two methods in WKNavigationDelegate are not be called.
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
fatalError("didFailProvisionalNavigation")
}
Seems there's a activityTimedOut happened. Any way to catch this error and reload the web view?
Thanks!

Blocked a frame with origin

I am trying to load javascript to a webview to change color of frame. I am getting "Blocked a frame with origin" error while javascript is being applied.
URL :
https://checkout-testing.herokuapp.com/v3/hosted/pay/7f4d4fd48adde85420e3
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let changeHtmlbuttonScript = """
document.getElementById(checkout).style.backgroundColor = "#0331FC"
"""
webView.evaluateJavaScript(changeHtmlbuttonScript) { (success, error) in
print("Error: \(error)")
}
}
I have tried setting "Arbitrary loads" property to false but no success. Does anyone know how to solve this.

WKWebView load fails randomly with NSURLErrorDomain Code -1200

I have a WKWebView created in IB that I load with an external url from Squarespace in viewWillAppear. As the page I'm loading is static I use cachePolicy .returnCacheDataElseLoad so I don't have to reload the page every time.
Usually it's working good. The page is loaded and the didFinish navigation delegate method is called. Now I started seeing some strange behavior, instead of getting the didFinish I get didFailProvisionalNavigation with SSL Error: NSURLErrorSecureConnectionFailed (-1200).
This behavior happens:
iOS 13.2.3
Only sometimes, the next time the same URL is working. Often deleting the app and reinstalling will help (removing the cache and reloading the page).
When on a mobile data connection (never when on WIFI)
Having a stable data connection (other pages in Safari are loading fine)
Only on 2 out of 8 test devices (With iPhone 11 Pro Max and iPhone X Max so far)
I don't think there are any issues with the SSL certificates because Squarespace handles that.
Any idea what can be wrong here? Otherwise what can I do to investigate more? I'm stuck!
The code:
class ViewController: UIViewController {
#IBOutlet weak var webView: WKWebView!
override func viewWillAppear(_ animated: Bool) {
if let url = URL(string: "https://www.subdomain.domain.com/article/en") {
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 30.0)
webView.navigationDelegate = self
webView.load(request)
}
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { }
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { }
}

evaluateJavascript is not executing function

How do i execute javascript function at runtime, the function to load the chat window does not get executed
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let javascript =
"const params = {typeId: ‘someid’, callback: getContextCallback} loadChatWindow(params)"
evaluateJavascript(javascript, completion:{ _ in })
}
try catching your error in evaluateJavascript completionHandler to see if your javascript string is correct or not (you need semicolon to separate the js statements as mentioned in the comment). also, evaluateJavascript is webView's method so it should be called like this:
webView.evaluateJavaScript(javascript) { (result, error) in
print(error as? String)}

Swift WKWebView crash on didFailProvisionalNavigation

We are encountering an intermittent (happens on some devices, some of the time) crash that we are having a hard time nailing down, and are unable to reproduce on-demand. This is related to Swift 3 and the WKWebView component, specifically its callback protocol crashes when attempting to get the error code via a switch statement. see below:
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
if let err = error as? URLError {
switch(err.code) { // Exception occurs on this line
case .cancelled:
Hint(hide: true)
case .cannotFindHost:
Hint(hide: false, hint:.CannotFindHost)
case .notConnectedToInternet:
Hint(hide: false, hint: .NoInternet)
case .resourceUnavailable:
Hint(hide: false)
case .timedOut:
Hint(hide: false)
default:
Hint(hide: false)
print("error code: " + String(describing: err.code) + " does not fall under known failures")
}
}
}
func Hint(hide: Bool, hint:SomeCustomEnum = SomeCustomEnum.Default) {
//Dosomething with ui to let user know something bad happened
}
the error stack indicates:
0 _BridgedStoredNSError.code.getter
1 _BridgedStoredNSError.code.getter
2 specialized WebKitController.webView(WKWebView, didFailProvisionalNavigation : WKNavigation!, withError : Error) -> ()
3 #obj WebKitController.webView(WKWebView, didFailProvisionalNavigation : WKNavigation!, withError : Error) -> ()
...
Reviewing the code it seems as if it should be effectively free from issues since the variable err should be successfully optionally-unwrapped as a valid URLError object by the time the switch statement is invoked. The switch statement at that point should be guaranteed a value in err.code since .code is not optional for URLError.
Attempts to artificially cause an error that might explain the issue have so far not provided much insight. ie. if I create my own custom error without a code property, then attempt to cast that as a URLError, it gracefully falls out of the optional assignment.
Any help or suggestions to revolve or even further troubleshoot is appreciated, in the mean time will continue to try to reproduce on a consistent basis.
When looking into the Swift Bug (https://bugs.swift.org) submission site I was able to find a description of the problem, ie. Error cast to URLError can result in the property .code being missing:
https://bugs.swift.org/browse/SR-3879?jql=text%20~%20%22URLError%22
This has a link to the following reference which seems to be the solution (still in process)
https://bugs.swift.org/browse/SR-3881
Effectively URLError is missing two .code definitions:
NSURLErrorAppTransportSecurityRequiresSecureConnection
NSURLErrorDataLengthExceedsMaximum
So if your encountering a crash when referencing the .code property of a URLError, you can check for it by casting to NSError and checking against the NSError .code property.
We are mitigating it with a temporary workaround until the bug is resolved (below only addresses the NSURLErrorAppTransportSecurityRequiresSecureConnection (int -1022) type failures):
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
let nserr = error as NSError
if nserr.code == -1022 {
Hint(hide: false, hint: .NSURLErrorAppTransportSecurityRequiresSecureConnection)
} else if let err = error as? URLError {
switch(err.code) { // Exception no longer occurs
case .cancelled:
Hint(hide: true)
case .cannotFindHost:
Hint(hide: false, hint:.CannotFindHost)
case .notConnectedToInternet:
Hint(hide: false, hint: .NoInternet)
case .resourceUnavailable:
Hint(hide: false)
case .timedOut:
Hint(hide: false)
default:
Hint(hide: false)
print("error code: " + String(describing: err.code) + " does not fall under known failures")
}
}
}
func Hint(hide: Bool, hint:SomeCustomEnum = SomeCustomEnum.Default) {
//Dosomething with ui to let user know something bad happened
}

Resources