我什么时候可以使用带有通用链接的 SFSafariViewController、WKWebView 或 UIWebView?

When can I use a SFSafariViewController, WKWebView, or UIWebView with universal links?

Universal Links section of the iOS App Search Programming Guide 中,Apple 表示:

If you instantiate a SFSafariViewController, WKWebView, or UIWebView object to handle a universal link, iOS opens your website in Safari instead of opening your app. However, if the user taps a universal link from within an embedded SFSafariViewController, WKWebView, or UIWebView object, iOS opens your app.

"handle a universal link"是什么意思?我永远不能用 SFSafariViewControllerWKWebViewUIWebView 打开给定的 URL 吗?它仅在 -[UIApplicationDelegate application:continueUserActivity:restorationHandler:] 期间适用,还是有超时?这是否意味着我们永远无法在 SFSafariViewControllerWKWebViewUIWebView 中打开 URL?

我不确定我是否完全理解你的问题。

只是为了介绍基础知识,我将允许 Apple 进行解释 what a Universal Link is

Universal links let users open your app when they tap links to your website within WKWebView and UIWebView views and Safari pages, in addition to links that result in a call to openURL:, such as those that occur in Mail, Messages, and other apps.

所以基本上,假设您正在使用 Twitter 客户端并浏览时间线,您会遇到一条包含以下 YouTube 视频的推文 link:https://youtu.be/ejQod8liXm0

如果您点击它,因为它是 HTTP URL,您会希望 Safari 打开 link。但是,我认为我们所有 iOS 开发人员几乎都同意 原生应用程序更好 ,因此更好的用户体验将 官方 YouTube 应用打开视频,甚至从您的第三方客户端。

这是"Universal Links"允许的;如果 YouTube 应用程序在 iOS 上注册为负责处理 https://www.youtube.com(*) link 的应用程序,iOS 生态系统中的每个人都会受益,如果我们遵循 API 规则。如果您 运行 一个网站并且您希望您的任何内容触发您的官方 iOS 应用程序打开(如果您的用户安装了它),或者如果用户安装了该应用程序则提示用户,也会发生同样的事情喜欢安装它以获得更好的用户体验(当然也是为了帮助您的业务)。

所以,抛开所有这些,让我们回到原文:

If you instantiate a SFSafariViewController, WKWebView, or UIWebView object to handle a universal link, iOS opens your website in Safari instead of opening your app. However, if the user taps a universal link from within an embedded SFSafariViewController, WKWebView, or UIWebView object, iOS opens your app.

这意味着,如果您的用户在您的应用中点击您的内容的通用 Link(例如:http://www.your-company.com/foo), and you do not detect this in your app's code via a regular expression for example, and instead instantiate a SFSafariViewController, WKWebView or UIWebView to open it as if it were a regular link to The New York Times 或其他内容,OS 将理解而不是在您的应用程序中打开它,您希望 Safari 为您处理它记住:Universal Links 的全部目的URL 由本机应用程序而非浏览器处理,让用户获得更好的体验。

第一句是这样说的。至于第二个,它清除了一个潜在的后续问题:如果用户从嵌入式浏览器 从另一个不是我的应用程序点击通用 Link 到我的内容怎么办? 然后,句子说,OS 将正常运行:它将打开您的应用程序,遵守通用 Link 规则。

TL;DR:您还需要在代码中检测您的应用程序内容的通用 Link,并处理它们。 iOS 不会为您处理。相反,如果您告诉 OS 在您的应用程序的嵌入式浏览器中打开一个通用 Link 到您的应用程序内容,它会完全按照指示执行。

编辑: 如果您需要帮助决定是询问 SFSafariViewController 还是 -openURL:options:completitionHandler: API 打开 URL , this link should help you; 我的建议是先使用-openURL:options:completitionHandler:,如果不成功,再使用SFSafariViewController或类似的

希望这对您有所帮助,并且我已经正确理解了您的问题。

干杯!快乐 iOS 11 编程! :)

我用下面的 Swift 4 class 解决了这个问题。如果可能,它还会使用嵌入式 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)
        }
    }
}