ios 为什么 WKWebView 不打开带有 target="_blank" 的链接?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25713069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is WKWebView not opening links with target="_blank"?
提问by stk
WKWebView
does not open any links which have target="_blank"
a.k.a. 'Open in new Window' attribute in their HTML <a href>
-Tag.
WKWebView
不会打开任何target="_blank"
在其 HTML<a href>
标签中具有“在新窗口中打开”属性的链接。
回答by Cloud Xu
My solution is to cancel the navigation and load the request with loadRequest: again. This will be come the similar behavior like UIWebView which always open new window in the current frame.
我的解决方案是取消导航并再次使用 loadRequest: 加载请求。这将是类似 UIWebView 的行为,它总是在当前帧中打开新窗口。
Implement the WKUIDelegate
delegate and set it to _webview.uiDelegate
. Then implement:
实现WKUIDelegate
委托并将其设置为_webview.uiDelegate
. 然后执行:
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}
回答by Bill Weinman
The answer from @Cloud Xu is the correct answer. Just for reference, here it is in Swift:
来自@Cloud Xu 的答案是正确的答案。仅供参考,这里是 Swift:
// this handles target=_blank links by opening them in the same view
func webView(webView: WKWebView!, createWebViewWithConfiguration configuration: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
if navigationAction.targetFrame == nil {
webView.loadRequest(navigationAction.request)
}
return nil
}
回答by muhasturk
To use latest version of Swift 4.2+
使用最新版本的 Swift 4.2+
import WebKit
Extend your class with WKUIDelegate
使用WKUIDelegate扩展您的课程
Set delegate for webview
为 webview 设置委托
self.webView.uiDelegate = self
Implement protocol method
实现协议方法
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
回答by stk
Add yourself as the WKNavigationDelegate
将自己添加为WKNavigationDelegate
_webView.navigationDelegate = self;
and implement following code in the delegate callback decidePolicyForNavigationAction:decisionHandler:
并在委托回调decisionPolicyForNavigationAction:decisionHandler中实现以下代码:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
//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.targetFrame) {
NSURL *url = navigationAction.request.URL;
UIApplication *app = [UIApplication sharedApplication];
if ([app canOpenURL:url]) {
[app openURL:url];
}
}
decisionHandler(WKNavigationActionPolicyAllow);
}
P.S.: This code is from my little project STKWebKitViewController
, which wraps a usable UI around WKWebView.
PS:这段代码来自我的小项目STKWebKitViewController
,它围绕 WKWebView 包装了一个可用的 UI。
回答by Boris Georgiev
If you've already set the WKWebView.navigationDelegate
如果您已经设置了 WKWebView.navigationDelegate
WKWebView.navigationDelegate = self;
WKWebView.navigationDelegate = self;
you just need to implement:
你只需要实现:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
BOOL shouldLoad = [self shouldStartLoadWithRequest:navigationAction.request]; // check the url if necessary
if (shouldLoad && navigationAction.targetFrame == nil) {
// WKWebView ignores links that open in new window
[webView loadRequest:navigationAction.request];
}
// always pass a policy to the decisionHandler
decisionHandler(shouldLoad ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
}
this way you don't need to implement the WKUIDelegate method.
这样您就不需要实现 WKUIDelegate 方法。
回答by Ugo Marinelli
None of those solutions worked for me, I did solve the issue by :
这些解决方案都不适合我,我确实通过以下方式解决了问题:
1) Implementing WKUIDelegate
1) 实现 WKUIDelegate
@interface ViewController () <WKNavigationDelegate, WKUIDelegate>
2) Setting the UIDelegate delegate of the wkWebview
2)设置wkWebview的UIDelegate委托
self.wkWebview.UIDelegate = self;
3) Implementing the createWebViewWithConfigurationmethod
3)实现createWebViewWithConfiguration方法
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
if (!navigationAction.targetFrame.isMainFrame) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[[UIApplication sharedApplication] openURL:[navigationAction.request URL]];
}
return nil; }
回答by Oliver Zhang
I confirm that Bill Weinman's Swift code is correct. But need to mention that you also need to delegate UIDelegate for it to work, in case you are new to iOS developing like me.
我确认 Bill Weinman 的 Swift 代码是正确的。但需要提及的是,您还需要委托 UIDelegate 才能使其工作,以防您像我一样是 iOS 开发新手。
Something like this:
像这样的东西:
self.webView?.UIDelegate = self
So there's three places that you need to make changes.
因此,您需要在三个地方进行更改。
回答by David H
You can also push another view controller, or open a new tab, etc:
您还可以推送另一个视图控制器,或打开一个新选项卡等:
func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
var wv: WKWebView?
if navigationAction.targetFrame == nil {
if let vc = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController") as? ViewController {
vc.url = navigationAction.request.URL
vc.webConfig = configuration
wv = vc.view as? WKWebView
self.navigationController?.pushViewController(vc, animated: true)
}
}
return wv
}
回答by 0xa6a
Cloud xu
's answer solves my issue.
Cloud xu
的答案解决了我的问题。
In case someone need the equivalent Swift(4.x/5.0) version, here is it:
如果有人需要等效的 Swift(4.x/5.0) 版本,这里是:
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if let frame = navigationAction.targetFrame,
frame.isMainFrame {
return nil
}
// for _blank target or non-mainFrame target
webView.load(navigationAction.request)
return nil
}
Of course you have to set webView.uiDelegate
firstly.
当然你webView.uiDelegate
要先设置。
回答by Vasily Bodnarchuk
Based on allen huang answer
Details
细节
- Xcode Version 10.3 (10G8), Swift 5
- Xcode 版本 10.3 (10G8),Swift 5
Targets
目标
- detect links with
target=“_blank”
push
view controller with webView if current controller hasnavigationController
present
view controller with webView in all other cases
- 检测链接
target=“_blank”
push
如果当前控制器有,则带有 webView 的视图控制器navigationController
present
在所有其他情况下带有 webView 的视图控制器
Solution
解决方案
webView.uiDelegate = self
// .....
extension ViewController: WKUIDelegate {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard navigationAction.targetFrame == nil,
let url = navigationAction.request.url else { return nil }
let vc = ViewController(url: url, configuration: configuration)
if let navigationController = navigationController {
navigationController.pushViewController(vc, animated: false)
return vc.webView
}
present(vc, animated: true, completion: nil)
return nil
}
}
Full sample
完整样品
Info.plist
信息表
add in your Info.plist transport security setting
添加您的 Info.plist 传输安全设置
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
ViewController
视图控制器
import UIKit
import WebKit
class ViewController: UIViewController {
private lazy var url = URL(string: "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_links_target")!
private weak var webView: WKWebView!
init (url: URL, configuration: WKWebViewConfiguration) {
super.init(nibName: nil, bundle: nil)
self.url = url
navigationItem.title = ""
}
required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
override func viewDidLoad() {
super.viewDidLoad()
initWebView()
webView.loadPage(address: url)
}
private func initWebView() {
let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
view.addSubview(webView)
self.webView = webView
webView.navigationDelegate = self
webView.uiDelegate = self
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
guard let host = webView.url?.host else { return }
navigationItem.title = host
}
}
extension ViewController: WKUIDelegate {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard navigationAction.targetFrame == nil,
let url = navigationAction.request.url else { return nil }
let vc = ViewController(url: url, configuration: configuration)
if let navigationController = navigationController {
navigationController.pushViewController(vc, animated: false)
return vc.webView
}
present(vc, animated: true, completion: nil)
return nil
}
}
extension WKWebView {
func loadPage(address url: URL) { load(URLRequest(url: url)) }
func loadPage(address urlString: String) {
guard let url = URL(string: urlString) else { return }
loadPage(address: url)
}
}
Storyboards
故事板
Version 1
版本 1
Version 2
版本 2