Why is WKWebView not opening links with target=“_blank”?
我的解决方案是取消导航,并再次使用loadRequest:加载请求。这将是类似于UIWebView的行为,该行为始终在当前框架中打开新窗口。
实现
1 2 3 4 5 6 7 8 | - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { if (!navigationAction.targetFrame.isMainFrame) { [webView loadRequest:navigationAction.request]; } return nil; } |
@Cloud Xu的答案是正确的答案。仅供参考,在Swift中:
1 2 3 4 5 6 7 | // 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 } |
使用最新版本的Swift 4.2+
1 | import WebKit |
使用WKUIDelegate扩展课程
为webview设置委托
1 | self.webView.uiDelegate = self |
实施协议方法
1 2 3 4 5 6 | func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { if navigationAction.targetFrame == nil { webView.load(navigationAction.request) } return nil } |
将您自己添加为WKNavigationDelegate
1 | _webView.navigationDelegate = self; |
并在委托回调DecisionPolicyForNavigationAction:decisionHandler中实现以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 | - (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); } |
附注:此代码来自我的小项目
如果您已经设置了WKWebView.navigationDelegate
WKWebView.navigationDelegate =自我;
您只需要实现:
1 2 3 4 5 6 7 8 9 10 11 12 | - (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); } |
这样,您无需实现WKUIDelegate方法。
如果有人需要等效的Swift(4.x / 5.0)版本,则为:
1 2 3 4 5 6 7 8 9 | 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 } |
当然,您必须首先设置
这些解决方案都不适合我,我确实通过以下方式解决了该问题:
1)实施WKUIDelegate
1 | @interface ViewController () <WKNavigationDelegate, WKUIDelegate> |
2)设置wkWebview的UIDelegate委托
1 | self.wkWebview.UIDelegate = self; |
3)实现createWebViewWithConfiguration方法
1 2 3 4 5 6 7 | - (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; } |
我确认Bill Weinman的Swift代码正确。但是需要指出的是,如果您像我一样不熟悉iOS,则还需要委派UIDelegate使其起作用。
像这样:
1 | self.webView?.UIDelegate = self |
因此,您需要在三个地方进行更改。
您还可以推送另一个视图控制器,或打开一个新标签,等等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 } |
基于艾伦·黄的回答
细节
- Xcode版本10.3(10G8),Swift 5
目标
-
检测与
target="_blank" 的链接 -
如果当前控制器具有
navigationController ,则带有WebView的push 视图控制器 -
在所有其他情况下,带有WebView的
present 视图控制器
解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } } |
完整样本
Info.plist
添加您的Info.plist传输安全设置
1 2 3 4 5 | <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> |
ViewController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 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) } } |
故事板
版本1
版本2
这对我有用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | -(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { if (!navigationAction.targetFrame.isMainFrame) { WKWebView *newWebview = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; newWebview.UIDelegate = self; newWebview.navigationDelegate = self; [newWebview loadRequest:navigationAction.request]; self.view = newWebview; return newWebview; } return nil; } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { decisionHandler(WKNavigationActionPolicyAllow); } - (void)webViewDidClose:(WKWebView *)webView { self.view = self.webView; } |
如您所见,我们要做的只是使用新的URL打开一个新的
我遇到了一些仅使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //MARK:- WKUIDelegate func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { NSLog(#function) if navigationAction.targetFrame == nil { NSLog("=> Create a new webView") let webView = WKWebView(frame: self.view.bounds, configuration: configuration) webView.uiDelegate = self webView.navigationDelegate = self self.webView = webView return webView } return nil } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | **Use following function to create web view** func initWebView(configuration: WKWebViewConfiguration) { let webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration) webView.uiDelegate = self webView.navigationDelegate = self view.addSubview(webView) self.webView = webView } **In View Did Load:** if webView == nil { initWebView(configuration: WKWebViewConfiguration()) } webView?.load(url: url1) **WKUIDelegate Method need to be implemented** extension WebViewController: WKUIDelegate { func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // push new screen to the navigation controller when need to open url in another"tab" print("url:\\(String(describing: navigationAction.request.url?.absoluteString))") if let url = navigationAction.request.url, navigationAction.targetFrame == nil { let viewController = WebViewController() viewController.initWebView(configuration: configuration) viewController.url1 = url DispatchQueue.main.async { [weak self] in self?.navigationController?.pushViewController(viewController, animated: true) } return viewController.webView } return nil } } extension WKWebView { func load(url: URL) { load(URLRequest(url: url)) } } |