WKWebView가 target =“_ blank”인 링크를 열지 않는 이유는 무엇입니까?


122

WKWebViewtarget="_blank"HTML <a href>태그 에 '새 창에서 열기'속성 이있는 링크는 열리지 않습니다 .


표시 정답 업데이트하십시오
Efren

답변:


184

내 해결책은 탐색을 취소하고 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;
}

4
이것은 정답입니다. 우리는 성공하지 못한 채 받아 들여진 대답을 시도했습니다. 그러나 @Cloud의 답변은 작동 하며 개발자 포럼의이 답변은 그 이유를 설명합니다.
Christopher Pickslay 2014 년

5
이 솔루션은 저에게 효과적이었습니다. UIDelegate이 메서드는 WKUIDelegatenot에 선언되어 있으므로 속성 을 설정하는 것을 잊지 마십시오 WKNavigationDelegate.
Taketo Sano 2014

1
좋아, 사람들이 WKWebView를 이와 같이 사용하고 싶어한다는 것을 알았습니다. 내 프로젝트 github.com/sticksen/STKWebKitViewController 의 동일한 WKWebView (위에 표시된대로)에서 target = _blank-Links를 열 수있는 가능성을 구현했습니다 .
stk

5
@ChristopherPickslay 내 WKWebView와 함께이 방법을 사용할 때 요청 URL은 항상 비어 있으므로 webview는 빈 흰색 페이지로 연결됩니다.
Jason Murray

1
게시물 데이터가있는 양식에서 '_blank'요청이 전송되면 게시물 데이터가 손실됩니다 !!! 도움이 필요하세요? @Cloud 우
앤드류

66

@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
}

2
대신 Safari에서 열려면 어떻게 작성 하시겠습니까? 또한이 작업을 수행하려면 뷰 컨트롤러에서 무엇을 참조해야합니까?
제드 그랜트

1
모바일 사파리에서 새 페이지를 열려면 다음 답변을 참조하십시오. stackoverflow.com/a/30604481/558789
Paul Bruneau

1
이것은 링크에 대해 작동하지만 JavaScript로 열린 새 창 (예 : window.open (url, "_blank"))을 감지하지 못하는 것 같습니다.
Crashalot

참고로 webView.loadRequest는 API의 최신 버전에서 webView.load로 이름이 변경되었습니다
Bill Weinman

52

최신 버전의 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
}

실제 복제가 아닙니다. 연결 한 답변에서 Swift 4.1 WKUIDelegate 프로토콜을 준수하지 않는 매개 변수의 선택성에 차이가 있습니다.
yakattack

안녕하세요, Pinterest URL로 WKWebview를로드 할 때 "Facebook으로 계속하기"를 열 수 없습니다. 이제 "Continuew with Google"에 대한 정보를 클릭하여 가져올 수 있습니다. 제발 도와주세요.
Nrv

wkwebview와 동일한 문제에 직면 해 있습니다. 내 앱에서 로그인 및 리디렉션이 작동하지 않습니다. 도움이 필요하십니까?
Jamshed Alam

1
누군가가 나를 도울 수 제발, 내가 wkwebview에 위임 uiDelegate를 할당하지만 구성이 호출되지 않는 그것의 방법은 웹보기를 만들
Chetan에 panchal

25

자신을 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);
}

추신 :이 코드는 STKWebKitViewControllerWKWebView 주변에 사용 가능한 UI를 래핑하는 내 작은 프로젝트 에서 가져온 것입니다.


1
오타가 있습니다. WKNavigationActionPolicy와 Allow 사이에 점이 없습니다.
chicken

@stk UIApplication이 Safari 앱에서 링크를 열 것인지 어떻게 이해할 수 있습니까? Appstore 링크 인 경우-Appstore 앱에서 ot를 열어야하지만 일반적인 웹 페이지 인 경우-동일한 WKWebView stackoverflow.com/questions/29056854/…
BergP

1
@LeoKoppelkamm 오타가 아니라 Swift가 아닌 Objective-C입니다. ;)
Ayan Sengupta 2016

1
이것은 링크에서 작동하지만 JavaScript로 열린 새 창을 감지하지 못하는 것 같습니다. 즉,window.open(url, "_blank")
Crashalot

@Crashalot window.open에 대한 해결책을 찾았습니까?

14

이미 WKWebView.navigationDelegate를 설정 한 경우

WKWebView.navigationDelegate = self;

다음을 구현하면됩니다.

- (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
이것은 링크에 대해 작동하지만 JavaScript로 열린 새 창 (예 : window.open (url, "_blank"))을 감지하지 못하는 것 같습니다.
Crashalot

@Crashalot이 답변을 확인 했습니까? stackoverflow.com/questions/33190234/wkwebview-and-window-open
Jose Rego

8

이러한 솔루션 중 어느 것도 나를 위해 일하지 않았으며 다음과 같이 문제를 해결했습니다.

1) WKUIDelegate 구현

@interface ViewController () <WKNavigationDelegate, WKUIDelegate>

2) wkWebview의 UIDelegate 델리게이트 설정

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;  }

나는 이것을 할 때 SIGABRT를 얻습니다. 작동하지 않습니다.
user2009449

8

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먼저 설정해야합니다 .


7

Bill Weinman의 Swift 코드가 올바른지 확인합니다. 하지만 저처럼 iOS 개발을 처음 접하는 경우 UIDelegate가 작동하도록 위임해야합니다.

이 같은:

self.webView?.UIDelegate = self

따라서 변경해야 할 세 곳이 있습니다.


코드를 입력하십시오.self.webView.UIDelegate = self
Henrik Petterson

묵시적인 것인지 확실하지 않지만이 코드 줄이 iOS 10에서 작동 ViewController하려면 WKUIDelegate. 즉class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
ltrainpr

4

다른 뷰 컨트롤러를 푸시하거나 새 탭을 열 수도 있습니다.

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. 이것이 사실이 아닌 시나리오를 설명 할 수 있습니까?
Mason G. Zhwiti

@ MasonG.Zhwiti 지난 가을 프로젝트에 WKWebViews를 적극적으로 사용했지만 그 이후로는 아무것도하지 않았으므로 질문에 답할 수 없습니다. 나는 위의 글을 게시했을 때 작동했습니다. vc.url을 설정하지 않고는 어떻게 작동하는지 이해할 수 없습니다.
David H

나는 당신이 만든 웹보기를 반환하기 때문에 그것이 작동하지 않는다고 생각하고, 당신이 그것을 생성하도록 요청한 것이 무엇이든 문제의 URL을로드하기 위해 웹보기를 사용하는 것을 처리합니다.
Mason G. Zhwiti

3

기반 알렌 황 대답

세부

  • Xcode 버전 10.3 (10G8), Swift 5

목표

  • 링크 감지 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를 생성하여 로그인했습니다. 이제 사용자가 로그인되었습니다. 이제 공유 창을 추적하는 방법은 무엇입니까?
Jamshed Alam

당신이 당신의 솔루션 내 인생 :) 저장 감사
삼랏 Pramanik을

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로 새 URL을 열고 닫을 가능성을 제어하는 ​​것 second webview입니다. 첫 번째에 표시 할 응답이 필요한 경우에만 가능합니다 .


1

을 사용하여 해결할 수없는 문제가 발생했습니다 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
}

0
**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)) }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.