WKWebView仍无法处理通用链接。

14

我有一个指向myApp的iOS通用链接。当我在另一个应用程序中点击该链接时,myApp会打开并完美地显示正确的回报,一切都正常。

但是myApp包括一个使用WKWebView的内置浏览器。当我从自己的内置浏览器中点击相同的通用链接时,iOS不会将链接发送到myApp,而是会获取一个网页。

Apple文档说:

如果您实例化了SFSafariViewController、WKWebView或UIWebView对象来处理通用链接,则 iOS 会在 Safari 中打开您的网站,而不是打开您的应用。然而,如果用户在嵌入的SFSafariViewController、WKWebView或UIWebView对象中点击了通用链接,则 iOS 会打开您的应用。

我注意到这个类似的问题,其中建议定义一个WKWebView委托。我在myApp中已经定义并使用了两个WKWebView委托,但没有帮助。这个其他问题有很多赞,但没有答案。

我的WKWebView实际上可以打开指向其他应用的通用链接。如果我在myApp WKWebView中点击链接https://open.spotify.com/artist/3hv9jJF3adDNsBSIQDqcjp,那么它会打开Spotify应用程序,而不打开任何中间的网页(即使在myApp中的长按菜单中没有提供“在Spotify中打开”选项)。但是当我从myApp中点击它时,iOS不会将通用链接传递给myApp

经过大量测试,我发现可以通过查找特定的URL并取消显示来防止与通用链接相关联的网页的显示:

func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) {
    if let urlString = navigationResponse.response.URL?.absoluteString {
        if urlString.hasPrefix(myULPrefix) { // it's a universal link targetted at myApp
            decisionHandler(.Cancel)
            return
        }
    }
    decisionHandler(.Allow)
}

我需要在响应的决策处理程序中执行此操作,而不是在动作的处理程序中执行。当我这样做时,通用链接将被排队等待发送至myApp但是,只有当我退出我的应用程序(例如,按下主页按钮)并重新启动时,iOS才会实际传递该消息。Apple文档中提到的appDelegate函数指定了传递此消息的内容。

func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {}

当我不使用更常规的深度链接(在Safari中点击通用链接以打开myApp)时,它没有被调用。这个函数是否有漏洞?还是一个特性?或者像往常一样,我只是在胡言乱语?

谢谢!


听起来可能是个bug?我建议通过https://bugreport.apple.com向苹果提出。 - Glen T
你有任何解决方案吗? - AntiMoron
我最近没有在那个项目上工作,所以不知道是否有任何变化。我们只能通过点击主页按钮并重新进入应用程序来获取链接。这对我们的用户来说相对较少,因此做更多的工作是没有用的。我个人没有将其提交给苹果作为错误。很抱歉现在无法提供更多帮助 :-( - emrys57
3个回答

1
如果您的wkwebview网页域名与您的通用链接域名相同,则会出现这种行为。简而言之,如果在Safari、SFSafariVC、WKWebView或UIWebView中打开的网页具有与您的应用程序链接(通用链接)域相同的域,则它不会触发通用链接。

{btsdaf} - Etienne Noël
我认为苹果没有记录这个。这种行为是我在通用链接的实际使用中观察到的。 - Dovakin Skyrim
苹果实际上已经记录了这种行为:当用户在Safari中浏览您的网站并点击同一域中的通用链接时,系统会在Safari中打开该链接,尊重用户最有可能继续使用浏览器的意图。如果用户在不同的域中点击通用链接,则系统会在您的应用程序中打开该链接。 - Petr Tomášek

0

我认为苹果是这样制作的,因为当应用程序运行时,您可以更自定义地处理它。

您找到了放置自己的处理程序调用的位置:

func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) {
    if let urlString = navigationResponse.response.URL?.absoluteString {
        if urlString.hasPrefix(myULPrefix) { // it's a universal link targetted at myApp
            decisionHandler(.Cancel)
            // put here the call to handle the link, for example:
            MyLinkHandler.handle(urlString)
            return
        }
    }
    decisionHandler(.Allow)
}

您可以在后台执行任何操作,而用户仍然停留在打开的页面上,或者您可以隐藏 Web 视图并打开应用程序的另一部分以显示适当的内容。


-1

我使用以下Swift 4类解决了这个问题。如果可能的话,它还使用了嵌入式Safari浏览器。您也可以在您的情况下遵循类似的方法。

import UIKit
import SafariServices

class OpenLink {
    static func inAnyNativeWay(url: URL, dontPreferEmbeddedBrowser: Bool = false) { // OPEN AS UNIVERSAL LINK IF EXISTS else : EMBEDDED or EXTERNAL
        if #available(iOS 10.0, *) {
            // Try to open with owner universal link app
            UIApplication.shared.open(url, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : true]) { (success) in
                if !success {
                    if dontPreferEmbeddedBrowser {
                        withRegularWay(url: url)
                    } else {
                        inAnyNativeBrowser(url: url)
                    }
                }
            }
        } else {
            if dontPreferEmbeddedBrowser {
                withRegularWay(url: url)
            } else {
                inAnyNativeBrowser(url: url)
            }
        }
    }
    private static func isItOkayToOpenUrlInSafariController(url: URL) -> Bool {
        return url.host != nil && (url.scheme == "http" || url.scheme == "https") //url.host!.contains("twitter.com") == false
    }
    static func inAnyNativeBrowser(url: URL) { // EMBEDDED or EXTERNAL BROWSER
        if isItOkayToOpenUrlInSafariController(url: url) {
            inEmbeddedSafariController(url: url)
        } else {
            withRegularWay(url: url)
        }
    }
    static func inEmbeddedSafariController(url: URL) { // EMBEDDED BROWSER ONLY
        let vc = SFSafariViewController(url: url, entersReaderIfAvailable: false)
        if #available(iOS 11.0, *) {
            vc.dismissButtonStyle = SFSafariViewController.DismissButtonStyle.close
        }
        mainViewControllerReference.present(vc, animated: true)
    }
    static func withRegularWay(url: URL) { // EXTERNAL BROWSER ONLY
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(url, options: [UIApplication.OpenExternalURLOptionsKey(rawValue: "no"):"options"]) { (good) in
                if !good {
                    Logger.log(text: "There is no application on your device to open this link.")
                }
            }
        } else {
            UIApplication.shared.openURL(url)
        }
    }
}

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