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
佐野武人2014

1
わかりました、このようにWKWebViewを使いたいと思っています。私のプロジェクトgithub.com/sticksen/STKWebKitViewControllerの同じWKWebViewでtarget = _blank-Linksを開く可能性を実装しました(上記を参照)。
stk 2014年

5
@ChristopherPickslay私のWKWebViewでこのメソッドを使用する場合、リクエストURLは常に空白です。そのため、webviewは空白の白いページに誘導します。
Jason Murray

1
投稿データのあるフォームから「_blank」リクエストを送信すると、投稿データが失われることがわかりました!!! 何か助けは?@Cloud Wu
Andrew

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で開く場合は、どのように記述しますか?また、これを機能させるために、View Controllerで何を参照する必要がありますか?
ジェドグラント

1
新しいページをモバイルサファリで開くには、次の回答を参照してください。stackoverflow.com
a

1
これはリンクに対しては機能しますが、JavaScriptで開かれた新しいウィンドウ、つまりwindow.open(url、 "_blank")を検出していないようです
Crashalot

FYI 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で続行」を開くことができませんでした。これで、「Googleで続行」をクリックして情報を取得できます。助けてください。
Nrv 2018

wkwebviewでも同じ問題に直面しています。ログインとリダイレクトが私のアプリで機能しませんでした。何か助け?
Jamshed Alam

1
誰かが私を助けることができるようにしてください、デリゲートuiDelegateをwkwebviewに割り当てましたが、そのメソッドで構成を含むWebビューを作成することが呼び出されていません
chetan panchal

25

自分をWKNavigationDelegateとして追加します

_webView.navigationDelegate = self;

デリゲートコールバックの次のコードを実装する決定ポリシーForNavigationAction: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);
}

PS:このコードはSTKWebKitViewController、使用可能なUIをWKWebViewの周りにラップした私の小さなプロジェクトからのものです。


1
タイプミスがあります。ドットはWKNavigationActionPolicy間行方不明と許可される

@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の解決策は見つかりましたか?
2016

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
ホセレゴ

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 2016

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

したがって、変更を加える必要のある場所は3つあります。


あなたのコードで入力し、それはです:self.webView.UIDelegate = self
ヘンリックPetterson

暗示されているかどうかはわかりませんが、このコード行をiOS 10で機能させるにViewControllerは、を継承する必要がありますWKUIDelegate。ieclass ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
ltrainpr 2016年

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ますか?設定していません。Webビューが正しく読み込まれています。また、私の経験では、createWebViewWithConfigurationいつnavigationAction.targetFrameが呼び出されるかを確認していnilます。これが当てはまらないシナリオを説明できますか?
メイソンG.ズウィティ

@ MasonG.Zhwiti私は昨年の秋にプロジェクトで積極的にWKWebViewsを使用していましたが、それ以降何もしていません-だから私は本当にあなたの質問に答えることはできません。上記を投稿したとき、それはうまくいきました。しかし、vc.urlを設定しないと、それがどのように機能するかを理解することはできません。
David H

あなたが作成したWebビューを返すので、それは機能しないと思います。そして(おそらく)作成を要求したものは、問題のURLをロードするためにWebビューを使用して処理します。
メイソンG.ズウィティ

3

アレン・ファンの回答に基づく

細部

  • Xcodeバージョン10.3(10G8)、Swift 5

対象

  • とのリンクを検出する target=“_blank”
  • push 現在のコントローラーが 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

ここに画像の説明を入力してください


こんにちは、facebookでログインした後、facebook共有の共有ウィンドウを同様に開く方法は?新しいwkwebviewを作成してログインしましたが、ユーザーはログインしました。共有ウィンドウを追跡する方法を教えてください。
Jamshed Alam

ありがとう、あなたの解決策は私の命を救います:)
Samrat 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からの応答をsecond webview表示する必要がある場合にのみ、新しいURLで新規を開いて、閉じる可能性を制御することです。


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.