WKWebView
ไม่เปิดลิงก์ใด ๆ ที่มีtarget="_blank"
แอตทริบิวต์ "Open in new Window" ใน HTML <a href>
-Tag
WKWebView
ไม่เปิดลิงก์ใด ๆ ที่มีtarget="_blank"
แอตทริบิวต์ "Open in new Window" ใน HTML <a href>
-Tag
คำตอบ:
วิธีแก้ปัญหาของฉันคือยกเลิกการนำทางและโหลดคำขอด้วย loadRequest: อีกครั้ง นี่จะเป็นลักษณะการทำงานที่คล้ายกันเช่น UIWebView ที่เปิดหน้าต่างใหม่ในเฟรมปัจจุบัน
ใช้ผู้รับมอบสิทธิ์และตั้งค่าให้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;
}
UIDelegate
คุณสมบัติเนื่องจากวิธีนี้WKUIDelegate
ไม่ได้ประกาศWKNavigationDelegate
ไว้
คำตอบจาก @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
}
หากต้องการใช้ Swift 4.2+ เวอร์ชันล่าสุด
import WebKit
ขยายชั้นเรียนของคุณด้วยWKUIDelegate
ตั้งค่าผู้รับมอบสิทธิ์สำหรับ webview
self.webView.uiDelegate = self
ใช้วิธีโปรโตคอล
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
เพิ่มตัวเองเป็นWKNavigationDelegate
_webView.navigationDelegate = self;
และใช้รหัสต่อไปนี้ในการตัดสินใจเรียกกลับของผู้รับมอบสิทธิ์การตัดสินใจนโยบายสำหรับการนำทาง: การตัดสินใจจัดการ:
- (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);
}
PS: รหัสนี้มาจากโครงการเล็ก ๆ ของฉันSTKWebKitViewController
ซึ่งรวม UI ที่ใช้งานได้รอบ ๆ WKWebView
window.open(url, "_blank")
หากคุณตั้งค่า WKWebView.navigationDelegate ไว้แล้ว
WKWebView.navigationDelegate = ตนเอง;
คุณต้องใช้:
- (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
วิธีแก้ปัญหาเหล่านั้นไม่ได้ผลสำหรับฉันฉันแก้ปัญหาโดย:
1) การใช้ WKUIDelegate
@interface ViewController () <WKNavigationDelegate, WKUIDelegate>
2) การตั้งค่า UIDelegate delegate ของ wkWebview
self.wkWebview.UIDelegate = self;
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; }
Cloud xu
คำตอบช่วยแก้ปัญหาของฉันได้
ในกรณีที่มีคนต้องการ 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
}
แน่นอนคุณต้องตั้งค่าwebView.uiDelegate
ประการแรก
ฉันยืนยันว่ารหัส Swift ของ Bill Weinman ถูกต้อง แต่ต้องพูดถึงว่าคุณต้องมอบหมาย UIDelegate เพื่อให้มันใช้งานได้ในกรณีที่คุณยังใหม่กับ iOS ที่พัฒนาเหมือนฉัน
สิ่งนี้:
self.webView?.UIDelegate = self
มีสามสถานที่ที่คุณต้องทำการเปลี่ยนแปลง
self.webView.UIDelegate = self
ViewController
WKUIDelegate
ieclass ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
คุณยังสามารถดันตัวควบคุมมุมมองอื่นหรือเปิดแท็บใหม่เป็นต้น:
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
หรือไม่? ฉันไม่ได้ตั้งค่าและกำลังโหลดมุมมองเว็บอย่างถูกต้อง นอกจากนี้จากประสบการณ์ของฉันฉันเห็นcreateWebViewWithConfiguration
ว่าถูกเรียกเมื่อnavigationAction.targetFrame
เป็นnil
เท่านั้น คุณสามารถอธิบายสถานการณ์ที่ไม่เป็นจริงได้หรือไม่?
ขึ้นอยู่กับคำตอบของอัลเลนฮวง
target=“_blank”
push
ดูตัวควบคุมด้วย webView หากตัวควบคุมปัจจุบันมี navigationController
present
ดูตัวควบคุมด้วย webView ในกรณีอื่น ๆ ทั้งหมด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 ของคุณ
<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)
}
}
เวอร์ชัน 1
เวอร์ชัน 2
สิ่งนี้ใช้ได้ผลสำหรับฉัน:
-(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;
}
อย่างที่คุณเห็นสิ่งที่เราทำที่นี่เป็นเพียงการเปิดwebView
url ใหม่และควบคุมความเป็นไปได้ในการปิดหากคุณต้องการคำตอบจากที่second webview
จะแสดงในครั้งแรก
ฉันพบปัญหาบางอย่างที่ไม่สามารถแก้ไขได้ด้วยการใช้webView.load(navigationAction.request)
. ดังนั้นฉันจึงใช้สร้าง webView ใหม่เพื่อทำและมันก็ใช้ได้ดี
//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)) }
}