Misael Landeros
Misael Landeros

Reputation: 595

why I can’t open a App Store link inside a web view?

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 = """


<a href="https://apps.apple.com/us/app/directorio-notarios-cdmx/id1544000342"> Appstore link dont open</a></span></span><br />

<a href="https://landercorp.mx" rel="noopener"> Normal link </a></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()
    }
}

Upvotes: 4

Views: 3801

Answers (1)

Shawn Frank
Shawn Frank

Reputation: 5143

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 = """
        <a href="https://apps.apple.com/us/app/directorio-notarios-cdmx/id1544000342"> Appstore link dont open</a></span></span><br />

        <a href="https://landercorp.mx" rel="noopener"> Normal link </a></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

  1. decidePolicyFor navigationAction (documentation link) to allow even urls that do not follow the HTTPs scheme to be allowed to be processed

  2. 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

  3. 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:

Open WKWebview target="_blank" mailto deeplink new tab app store link or open an App Store link inside a web view

Upvotes: 7

Related Questions