在 Safari 中打开 WKWebview target="_blank" link
Open a WKWebview target="_blank" link in Safari
我正在尝试让我的混合 IOS 应用程序使用 Swift 和 WKWebviews 打开具有 target="_blank"
的 link 或者 URL在 Mobile Safari 中包含 http://
、https://
或 mailto:
。
从 this answer 我得到这个代码。
func webView(webView: WKWebView!, createWebViewWithConfiguration configuration: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
if navigationAction.targetFrame == nil {
webView.loadRequest(navigationAction.request)
}
return nil
}
首先,这对我没有任何作用。其次,我希望它在新 window 中打开。我发现这段代码应该做类似的事情...
if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") {
UIApplication.sharedApplication().openURL(requestUrl)
}
我如何将这两个放在一起并让它们工作?我需要在 ViewController 声明中添加什么才能使其生效?
在 (from here)
override func loadView() {
super.loadView()
self.webView.navigationDelegate = self
self.webView.UIDelegate = self //must have this
}
然后添加函数(from here, with additions)...
func webView(webView: WKWebView,
createWebViewWithConfiguration configuration: WKWebViewConfiguration,
forNavigationAction navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
var url = navigationAction.request.URL
if url.description.lowercaseString.rangeOfString("http://") != nil || url.description.lowercaseString.rangeOfString("https://") != nil || url.description.lowercaseString.rangeOfString("mailto:") != nil {
UIApplication.sharedApplication().openURL(url)
}
}
return nil
}
先加上WKNavigationDelegate
和webviewWk.navigationDelegate = self
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
//this is a 'new window action' (aka target="_blank") > open this URL externally. If we´re doing nothing here, WKWebView will also just do nothing. Maybe this will change in a later stage of the iOS 8 Beta
if navigationAction.navigationType == WKNavigationType.LinkActivated {
println("here link Activated!!!")
let url = navigationAction.request.URL
let shared = UIApplication.sharedApplication()
let urlString = url!.absoluteString
if shared.canOpenURL(url!) {
shared.openURL(url!)
}
decisionHandler(WKNavigationActionPolicy.Cancel)
}
decisionHandler(WKNavigationActionPolicy.Allow)
}
代码已更新 iOS 10 Swift 3:
override func loadView() {
super.loadView()
self.webView.navigationDelegate = self
self.webView.uiDelegate = self //must have this
}
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
if url.description.lowercased().range(of: "http://") != nil ||
url.description.lowercased().range(of: "https://") != nil ||
url.description.lowercased().range(of: "mailto:") != nil {
UIApplication.shared.openURL(url)
}
}
return nil
}
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil, let url = navigationAction.request.url, let scheme = url.scheme {
if ["http", "https", "mailto"].contains(where: { [=10=].caseInsensitiveCompare(scheme) == .orderedSame }) {
UIApplication.shared.openURL(url)
}
}
return nil
}
Swift 4.2
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
if navigationAction.navigationType == WKNavigationType.linkActivated {
print("here link Activated!!!")
if let url = navigationAction.request.url {
let shared = UIApplication.shared
if shared.canOpenURL(url) {
shared.open(url, options: [:], completionHandler: nil)
}
}
decisionHandler(.cancel)
}
else {
decisionHandler(.allow)
}
}
虽然上述某些解决方案在一定程度上起作用,但问题是所有 link 都开始在外部打开,而不仅仅是那些没有像 mailto 那样遵循 HTTPs url 方案的那些, 空白, 深links 等
我实现了这些 WKNavigationDelegate
功能
decidePolicyFor navigationAction
(documentation link) 甚至允许 url 不遵循 HTTPs 方案的被允许处理
this navigation fail delegate function webView didFailProvisionalNavigation
并检查 iOS 是否可以处理在新选项卡中打开、邮件、深度 link 等万一它会打开应用程序商店
您也可以实现与本文中第 2 点相同的逻辑
WKNavigationDelegate function以防万一
代码如下:
class ViewController: UIViewController, WKNavigationDelegate
{
// Initialize the webview anywhere you wish
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
let html = """
<a href="https://apps.apple.com/us/app/directorio-notarios-cdmx/id1544000342"> App store Deep link usually doesn't 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)
}
// 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)
}
}
}
}
}
这样,两种情况都得到处理,其中遵循 HTTPs url 方案而不是
我正在尝试让我的混合 IOS 应用程序使用 Swift 和 WKWebviews 打开具有 target="_blank"
的 link 或者 URL在 Mobile Safari 中包含 http://
、https://
或 mailto:
。
从 this answer 我得到这个代码。
func webView(webView: WKWebView!, createWebViewWithConfiguration configuration: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
if navigationAction.targetFrame == nil {
webView.loadRequest(navigationAction.request)
}
return nil
}
首先,这对我没有任何作用。其次,我希望它在新 window 中打开。我发现这段代码应该做类似的事情...
if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") {
UIApplication.sharedApplication().openURL(requestUrl)
}
我如何将这两个放在一起并让它们工作?我需要在 ViewController 声明中添加什么才能使其生效?
在 (from here)
override func loadView() {
super.loadView()
self.webView.navigationDelegate = self
self.webView.UIDelegate = self //must have this
}
然后添加函数(from here, with additions)...
func webView(webView: WKWebView,
createWebViewWithConfiguration configuration: WKWebViewConfiguration,
forNavigationAction navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
var url = navigationAction.request.URL
if url.description.lowercaseString.rangeOfString("http://") != nil || url.description.lowercaseString.rangeOfString("https://") != nil || url.description.lowercaseString.rangeOfString("mailto:") != nil {
UIApplication.sharedApplication().openURL(url)
}
}
return nil
}
先加上WKNavigationDelegate
和webviewWk.navigationDelegate = self
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
//this is a 'new window action' (aka target="_blank") > open this URL externally. If we´re doing nothing here, WKWebView will also just do nothing. Maybe this will change in a later stage of the iOS 8 Beta
if navigationAction.navigationType == WKNavigationType.LinkActivated {
println("here link Activated!!!")
let url = navigationAction.request.URL
let shared = UIApplication.sharedApplication()
let urlString = url!.absoluteString
if shared.canOpenURL(url!) {
shared.openURL(url!)
}
decisionHandler(WKNavigationActionPolicy.Cancel)
}
decisionHandler(WKNavigationActionPolicy.Allow)
}
代码已更新 iOS 10 Swift 3:
override func loadView() {
super.loadView()
self.webView.navigationDelegate = self
self.webView.uiDelegate = self //must have this
}
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
if url.description.lowercased().range(of: "http://") != nil ||
url.description.lowercased().range(of: "https://") != nil ||
url.description.lowercased().range(of: "mailto:") != nil {
UIApplication.shared.openURL(url)
}
}
return nil
}
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil, let url = navigationAction.request.url, let scheme = url.scheme {
if ["http", "https", "mailto"].contains(where: { [=10=].caseInsensitiveCompare(scheme) == .orderedSame }) {
UIApplication.shared.openURL(url)
}
}
return nil
}
Swift 4.2
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
if navigationAction.navigationType == WKNavigationType.linkActivated {
print("here link Activated!!!")
if let url = navigationAction.request.url {
let shared = UIApplication.shared
if shared.canOpenURL(url) {
shared.open(url, options: [:], completionHandler: nil)
}
}
decisionHandler(.cancel)
}
else {
decisionHandler(.allow)
}
}
虽然上述某些解决方案在一定程度上起作用,但问题是所有 link 都开始在外部打开,而不仅仅是那些没有像 mailto 那样遵循 HTTPs url 方案的那些, 空白, 深links 等
我实现了这些 WKNavigationDelegate
功能
decidePolicyFor navigationAction
(documentation link) 甚至允许 url 不遵循 HTTPs 方案的被允许处理this navigation fail delegate function
webView didFailProvisionalNavigation
并检查 iOS 是否可以处理在新选项卡中打开、邮件、深度 link 等万一它会打开应用程序商店您也可以实现与本文中第 2 点相同的逻辑 WKNavigationDelegate function以防万一
代码如下:
class ViewController: UIViewController, WKNavigationDelegate
{
// Initialize the webview anywhere you wish
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
let html = """
<a href="https://apps.apple.com/us/app/directorio-notarios-cdmx/id1544000342"> App store Deep link usually doesn't 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)
}
// 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)
}
}
}
}
}
这样,两种情况都得到处理,其中遵循 HTTPs url 方案而不是