为什么我不能在 Web 视图中打开应用商店链接?

4

我一直收到这个错误:

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

常规链接可正常工作,但AppStore链接无法工作。

我想要的是打开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()
    }
}
1个回答

7
一些链接可能会触发动作/重定向到非HTTPs的URL方案,例如:
  • _blank打开一个新标签页
  • mailto启动邮件应用程序
  • 其他一些深层链接技术(熟悉设备操作系统的技术)
我认为应用商店链接使用了上述方法的组合,而WKWebView无法处理非HTTPs方案。你可以通过监听在WKNavigationDelegate中失败的URL并进行相应处理。
我没有使用SwiftUI,但我认为你可以理解这个情况。
使用与您相同的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 (文档链接)来允许处理不遵循HTTPs协议的网址

  2. 实现此导航失败的委托函数webView didFailProvisionalNavigation,并检查 iOS 是否可以在新选项卡、邮件、深度链接等中打开,因此在您的情况下它将打开应用商店

  3. 您还可以在此WKNavigationDelegate函数中实现与点2相同的逻辑以备万一

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

试试这个,看看是否解决了你的问题。在我这边,这两个链接似乎都能正常工作: 打开WKWebView target="_blank" mailto deeplink新标签页应用商店链接或在Web视图中打开App Store链接

2
谢谢!昨天我阅读了所有与堆栈溢出相关的问题,但没有找到一些有帮助的答案,这不仅是一个清晰的答案,而且是一个非常完整的答案。 - Misael Landeros
哇,这太棒了! - user3413723
如果您想避免使用原始字符串而导致错误,可以使用一个常量:NSURLErrorFailingURLStringErrorKey。 - James Wolfe
谢谢您的建议@JamesWolfe,只是为了明确,您是指用NSURLErrorFailingURLStringErrorKey替换“NSErrorFailingURLKey”吗? - Shawn Frank
我相信是的 :) - James Wolfe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接