Câu trả lời:
Giải pháp của tôi là hủy điều hướng và tải lại yêu cầu bằng loadRequest:. Đây sẽ là hành vi tương tự như UIWebView luôn mở cửa sổ mới trong khung hiện tại.
Triển khai WKUIDelegate
ủy quyền và đặt nó thành _webview.uiDelegate
. Sau đó thực hiện:
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}
UIDelegate
tính, vì phương thức này được khai báo bằng WKUIDelegate
không WKNavigationDelegate
.
Câu trả lời từ @Cloud Xu là câu trả lời chính xác. Chỉ để tham khảo, đây là trong 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
}
Để sử dụng phiên bản mới nhất của Swift 4.2+
import WebKit
Mở rộng lớp học của bạn với WKUIDelegate
Đặt ủy quyền cho chế độ xem web
self.webView.uiDelegate = self
Triển khai phương pháp giao thức
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
Thêm chính bạn làm WKNavigationDelegate
_webView.navigationDelegate = self;
và triển khai mã sau trong lệnh gọi lại ủy quyền quyết địnhPolicyForNavigationAction: quyết địnhHandler:
- (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);
}
Tái STKWebKitViewController
bút : Mã này là từ dự án nhỏ của tôi , bao bọc một giao diện người dùng có thể sử dụng xung quanh WKWebView.
window.open(url, "_blank")
Nếu bạn đã đặt WKWebView.navigationDelegate
WKWebView.navigationDelegate = bản thân;
bạn chỉ cần thực hiện:
- (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);
}
theo cách này, bạn không cần triển khai phương thức WKUIDelegate.
Không có giải pháp nào trong số đó hiệu quả với tôi, tôi đã giải quyết vấn đề bằng cách:
1) Triển khai WKUIDelegate
@interface ViewController () <WKNavigationDelegate, WKUIDelegate>
2) Đặt đại biểu UIDelegate của wkWebview
self.wkWebview.UIDelegate = self;
3) Triển khai phương thức 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; }
Cloud xu
Câu trả lời giải quyết vấn đề của tôi.
Trong trường hợp ai đó cần phiên bản Swift (4.x / 5.0) tương đương, đây là nó:
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
}
Tất nhiên bạn phải đặt webView.uiDelegate
trước.
Tôi xác nhận rằng mã Swift của Bill Weinman là chính xác. Nhưng cần đề cập rằng bạn cũng cần ủy quyền cho UIDelegate để nó hoạt động, trong trường hợp bạn mới phát triển iOS như tôi.
Một cái gì đó như thế này:
self.webView?.UIDelegate = self
Vì vậy, có ba điểm mà bạn cần thực hiện thay đổi.
self.webView.UIDelegate = self
ViewController
cần kế thừa WKUIDelegate
. tức làclass ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
Bạn cũng có thể đẩy một bộ điều khiển chế độ xem khác hoặc mở một tab mới, v.v.:
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
}
vc.url
không? Tôi không đặt nó và chế độ xem web đang được tải đúng cách. Ngoài ra, theo kinh nghiệm của tôi, tôi chỉ thấy createWebViewWithConfiguration
được gọi khi navigationAction.targetFrame
được nil
. Bạn có thể mô tả một kịch bản mà điều này sẽ không đúng không?
Dựa trên câu trả lời của allen huang
target=“_blank”
push
xem bộ điều khiển với webView nếu bộ điều khiển hiện tại có navigationController
present
xem bộ điều khiển với webView trong tất cả các trường hợp khácwebView.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
thêm vào cài đặt bảo mật truyền tải Info.plist của bạn
<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)
}
}
Phiên bản 1
Phiên bản 2
Điều này đã làm việc cho tôi:
-(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;
}
Như bạn có thể thấy, những gì chúng tôi làm ở đây chỉ là mở một webView
url mới và kiểm soát khả năng bị đóng, chỉ cần bạn cần phản hồi từ đó second webview
sẽ được hiển thị ở lần đầu tiên.
Tôi gặp phải một số vấn đề không thể giải quyết bằng cách sử dụng webView.load(navigationAction.request)
. Vì vậy, tôi sử dụng tạo một webView mới để làm và nó hoạt động tốt.
//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
}
**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)) }
}