为什么我无法在 Web 视图中打开 App Store link?

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

我总是遇到这个错误:

WebPageProxy::didFailProvisionalLoadForFrame: frameID=3, domain=WebKitErrorDomain, code=102

普通链接有效,但 AppStore 链接无效

我想要的是 Link 打开 AppStore 我不能在本地打开,因为网络是从 Qualtrics 网络加载的。

我尝试添加 navigationAction 函数,但这不起作用,我猜测请求可能需要一些时间,我需要一种以异步方式加载数据的方法,但老实说我真的不知道

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()
    }
}

某些 link 点按它们可能会激活操作/重定向 url 非 HTTP 方案,例如

  • _blank 打开新标签页
  • mailto 启动邮件应用程序
  • 设备操作系统熟悉的一些其他深度link技术

我相信应用程序商店 link 使用了上述的组合,WKWebView 无法处理非 HTTPs 方案。

您可以做的是监听使用 WKNavigationDelegate 失败的 URL 并相应地处理它们

我没有使用 SwiftUI,但我想你可以得到图片。

使用与 links

相同的 HTML 进行设置
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)
    }
}

然后我实现这些WKNavigationDelegate功能

  1. decidePolicyFor navigationAction (documentation link) 甚至允许 url 不遵循 HTTPs 方案的被允许处理

  2. this navigation fail delegate function webView didFailProvisionalNavigation 并检查 iOS 是否可以处理在新选项卡中打开、邮件、深度 link 等如果它会打开应用程序商店

  3. 您也可以实现与本文中第 2 点相同的逻辑 WKNavigationDelegate function以防万一

// 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)
            }
        }
    }
}

试一试,看看是否能解决您的问题。在我这边,两个 link 似乎都工作正常: