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) { }
}
Related
I'm getting always this error :
WebPageProxy::didFailProvisionalLoadForFrame: frameID=3, domain=WebKitErrorDomain, code=102
Normal links are working but the AppStore one is not working
what I want is the Link to open the AppStore I can't do it locally because the web is loaded from a Qualtrics web.
I try it adding the navigationAction function but that doesn't work, what I'm guessing is that maybe the request is taking some time and i need a way of load that data on an async way but to be honest i really dont know
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let html = """
Appstore link dont open</span></span><br />
Normal link </span></span><br />
"""
var loadStatusChanged: ((Bool, Error?) -> Void)? = nil
func makeCoordinator() -> WebView.Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
view.navigationDelegate = context.coordinator
view.loadHTMLString(html, baseURL: nil)
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
class Coordinator: NSObject, WKNavigationDelegate {
let parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
}
}
struct ContentView: View {
var body: some View {
WebView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Some links on tapping them might activate actions / redirect with url schemes that are non HTTPs like
_blank to open a new tab
mailto to launch the mail application
some other deep link techniques familiar to device OSs
I believe the app store link uses a combination of the above and WKWebView cannot handle non HTTPs schemes.
What you can do is to listen to URLs that fail using WKNavigationDelegate and handle them accordingly
I am not using SwiftUI but I think you can get the picture.
Set up using the same HTML as you with both the links
class ViewController: UIViewController, WKNavigationDelegate
{
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
let html = """
Appstore link dont open</span></span><br />
Normal link </span></span><br />
"""
let webview = WKWebView()
webview.frame = view.bounds
webview.navigationDelegate = self
view.addSubview(webview)
webview.loadHTMLString(html, baseURL: nil)
}
}
Then I implement these WKNavigationDelegate functions
decidePolicyFor navigationAction (documentation link) to allow even urls that do not follow the HTTPs scheme to be allowed to be processed
this navigation fail delegate function webView didFailProvisionalNavigation and check if iOS can handle the open in a new tab, mail, deep link etc so in your case it would open the app store
You could also implement the same logic as point 2 in this
WKNavigationDelegate function just in case
// MARK: WKNavigationDelegates
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
{
decisionHandler(.allow)
}
func webView(_ webView: WKWebView,
didFailProvisionalNavigation navigation: WKNavigation!,
withError error: Error)
{
manageFailedNavigation(webView,
didFail: navigation,
withError: error)
}
func webView(_ webView: WKWebView,
didFail navigation: WKNavigation!,
withError error: Error)
{
manageFailedNavigation(webView,
didFail: navigation,
withError: error)
}
private func manageFailedNavigation(_ webView: WKWebView,
didFail navigation: WKNavigation!,
withError error: Error)
{
// Check if this failed because of mailto, _blank, deep links etc
// I have commented out how to check for a specific case like open in a new tab,
// you can try to handle each case as you wish
if error.localizedDescription
== "Redirection to URL with a scheme that is not HTTP(S)"
//let url = webView.url, url.description.lowercased().range(of: "blank") != nil
{
// Convert error to NSError so we can access the url
let nsError = error as NSError
// Get the url from the error
// This key could change in future iOS releases
if let failedURL = nsError.userInfo["NSErrorFailingURLKey"] as? URL
{
// Check if the action can be handled by iOS
if UIApplication.shared.canOpenURL(failedURL)
{
// Request iOS to open handle the link
UIApplication.shared.open(failedURL, options: [:],
completionHandler: nil)
}
}
}
}
Give this a go and check if this fixes your issue. On my side, both links seem to work fine:
Some specific URL https://stg.express.rakuten.co.jp/?tn=600149999205 when I open the page in WKWebView it's calling didCommitNavigation multiple time (2 times) but it's calling didFinishNavigation delegate method only for one time.
Does anyone have an idea why it's happening?
I referred this post but in that case, webViewDidStartLoad/webViewDidFinishLoad called multiple time for a single request while in my case it's calling didCommitNavigation multiple times.
public func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
}
open func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
I'm trying to load a local web, but is not working, only a white screen is being displayed.
let zipName = webSection?.zipResource?.zipName?.lowercased() {
let zipPath = ProjectPath.path.appending(zipName.deletingPathExtension).appending(pathComponent: "index.html")
let url = URL(fileURLWithPath: zipPath)
//webView.loadFileURL(url, allowingReadAccessTo: url) //suppossedly new method for loading local websites, but it haves same behaviour, blank screen
webView.load(URLRequest(url: url))
In Android, I can see in logcat which errors is generating the webview when no content is being displayed, but here in Xcode I can't see nothing in the console. How can i see which errors is giving the WKWebView?
Implement webView navigation delegate in viewDidLoad
self.webView.navigationDelegate = self
extension ViewController : WKNavigationDelegate {
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print(error.localizedDescription)
}
}
I am using WKWebView for my WebViewController in my app and I spot one problem with one URL
"http://www.viator.com/tours/San-Francisco/San-Francisco-Vista-Grande-Helicopter-Tour/d651-3538VISTAGRANDE?eap=brand-subbrand-75523&aid=vba75523en" there is no navigation through the web site when I tap some other event page nothing happens. Does anyone have any ideas about how to deal with that?
If you're talking about links opening in a new window, indeed, they don't create a new navigation action. But you can still intercept them, and load the request manually.
If your webview does not have a custom uiDelegate already, assign it to your view controller or something else, and then do something like this:
extension SomeViewController: WKUIDelegate {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
// Intercept target=_blank links
guard
navigationAction.targetFrame == nil,
let url = navigationAction.request.url else {
return nil
}
let request = URLRequest(url: url)
webView.load(request)
return nil
}
}
I'm using WKWebView to browse the specific website.
WKWebView instance loads initial page of the website by URL with method load(_ request: URLRequest) -> WKNavigation? Until load request isn't completed I see white screen. Can WKWebView show already loaded parts of the webpage while the rest of the webpage is loading?
Can UIWebView do this trick?
if white screen is your issue, i recommend you to display an custom progress indicator over the webView or some Animation view over your webView.
Once the loading is completed hide the progress indicator.
Start your Animation at:
optional func webView(_ webView: WKWebView,
didStartProvisionalNavigation navigation: WKNavigation!)
{
//Start Progress indicator animation
}
End/Hide your Animation/Progress View at:
optional func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!)
{
//Stop Progress indicator animation
}
In my case progressive loading started to work when i have added delegate WKWebViewNavigationDelegate to WKWebview and function
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)
If this func was not added, Web page did not rendered before all content was downloaded in all cases