WKWebView neden target = "_ blank" ile bağlantıları açmıyor?


122

WKWebViewsahip herhangi bir bağlantı açılmaz target="_blank"onların HTML değer kümesi 'yeni pencere aç' aka <a href>Etiketleme-.


lütfen işaretlenen doğru yanıtı güncelleyin
Efren

Yanıtlar:


184

Benim çözümüm navigasyonu iptal etmek ve talebi loadRequest ile tekrar yüklemek: tekrar. Bu, geçerli çerçevede her zaman yeni pencere açan UIWebView gibi benzer bir davranış olacaktır.

Uygulamak WKUIDelegatetemsilci ve ayarlayın _webview.uiDelegate. Ardından uygulayın:

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
  if (!navigationAction.targetFrame.isMainFrame) {
    [webView loadRequest:navigationAction.request];
  }

  return nil;
}

4
Bu doğru cevap. Kabul edilen yanıtı başarılı olmadan denedik. Ancak @ Cloud'un cevabı işe yarıyor ve geliştirici forumlarındaki bu yanıt nedenini açıklıyor.
Christopher Pickslay

5
Bu çözüm benim için çalıştı. UIDelegateÖzelliği ayarlamayı unutmayın , çünkü bu yöntemler WKUIDelegatenot içinde bildirilmiştir WKNavigationDelegate.
2014, 05

1
Tamam, insanların WKWebView'ı bu şekilde kullanmak istediğini görüyorum. Github.com/sticksen/STKWebKitViewController projemde aynı WKWebView'da (yukarıda gösterildiği gibi) target = _blank-Links'i açma olasılığını uyguladım .
stk

5
@ChristopherPickslay bu yöntemi WKWebView ile kullanırken istek url'si her zaman boştur, bu nedenle web görünümü boş bir beyaz sayfaya yönlendirir, herhangi bir fikir?
Jason Murray

1
Yazı verileri içeren bir formdan '_blank' isteği gönderildiğinde, gönderi verilerinin kaybolacağını görüyorum !!! Herhangi bir yardım? @Cloud Wu
Andrew

66

@Cloud Xu'nun cevabı doğru cevaptır. Sadece referans için, işte Swift'de:

// 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
Bunun yerine Safari'de açılmasını isteseydiniz nasıl yazardınız? Ayrıca bunun çalışması için görünüm denetleyicisinde neye başvurmam gerekir?
Jed Grant

1
Yeni sayfanın mobil safaride açılmasını sağlamak için şu cevaba bakın: stackoverflow.com/a/30604481/558789
Paul Bruneau

1
Bu bağlantılar için çalışıyor, ancak JavaScript ile açılan yeni pencereleri, yani window.open (url, "_blank")
Crashalot

Bilginize webView.loadRequest, API'nin son sürümlerinde webView.load olarak yeniden adlandırıldı
Bill Weinman

52

Swift 4.2+ en son sürümünü kullanmak için

import WebKit

İle sınıfınızı genişletin WKUIDelegate

Web görünümü için temsilci ayarlayın

self.webView.uiDelegate = self

Protokol yöntemini uygulayın

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame == nil {
        webView.load(navigationAction.request)
    }
    return nil
}

Gerçek bir kopya değil. Bağlandığınız yanıtta Swift 4.1 WKUIDelegate protokolüne uymayan parametrelerin isteğe bağlı olarak farklılıkları var.
yakattack

Merhaba, WKWebview'i Pinterest URL'si ile yüklerken, "Facebook ile Devam Et" i açamadım. Artık tıklayıp "Google ile Devam Et" ile ilgili bilgileri alabiliyorum. Lütfen bana yardım edin.
Nrv

Wkwebview ile aynı sorunla karşılaşıyorum; giriş ve yönlendirme uygulamamda çalışmıyor. Herhangi bir yardım ?
Jamshed Alam

1
lütfen herkes bana yardım edebilir, uiDelegate'i wkwebview'a atadım ama onun yöntemi yapılandırma ile web görünümü oluşturma yöntemi çağrılmıyor
chetan panchal

25

Kendinizi WKNavigationDelegate olarak ekleyin

_webView.navigationDelegate = self;

ve temsilci geri aramasında aşağıdaki kodu uygulayınkaradePolicyForNavigationAction: kararHandler:

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

Not: Bu kod, STKWebKitViewControllerWKWebView etrafındaki kullanılabilir bir kullanıcı arayüzünü saran küçük projemden.


1
Bir yazım hatası var. WKNavigationActionPolicy ve Allow arasında bir nokta eksik
chicken

@stk UIApplication'ın Safari uygulamasında bağlantıyı açıp açmayacağını nasıl anlayabilirim? Appstore bağlantısı ise - Appstore uygulamasında ot açmam gerekiyor, ancak bu normal web sayfasındaysa - aynı WKWebView stackoverflow.com/questions/29056854/…
BergP

1
@LeoKoppelkamm Bu bir yazım hatası değil, Objective-C Swift değil. ;)
Ayan Sengupta

1
Bu bağlantılar için çalışıyor, ancak JavaScript ile açılan yeni pencereleri algılamıyor gibi görünüyor, yaniwindow.open(url, "_blank")
Crashalot

@Crashalot window.open için çözüm buldunuz mu?
Sam

14

WKWebView.navigationDelegate'i zaten ayarladıysanız

WKWebView.navigationDelegate = self;

sadece uygulamanız gerekir:

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

bu şekilde WKUIDelegate yöntemini uygulamanıza gerek kalmaz.


1
Bu bağlantılar için çalışıyor, ancak JavaScript ile açılan yeni pencereleri, yani window.open (url, "_blank")
Crashalot


8

Bu çözümlerin hiçbiri benim için işe yaramadı, sorunu şu şekilde çözdüm:

1) WKUIDelegate'i Uygulama

@interface ViewController () <WKNavigationDelegate, WKUIDelegate>

2) wkWebview'un UIDelegate delegesini ayarlama

self.wkWebview.UIDelegate = self;

3) createWebViewWithConfiguration yönteminin uygulanması

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

Bunu yaparken sadece bir SIGABRT alıyorum. Çalışmıyor.
user2009449

8

Cloud xu'nin cevabı sorunumu çözdü.

Birinin eşdeğer Swift (4.x / 5.0) sürümüne ihtiyaç duyması durumunda, işte:

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
}

Elbette webView.uiDelegateönce ayarlamalısın .


7

Bill Weinman'ın Swift kodunun doğru olduğunu onaylıyorum. Ancak benim gibi iOS geliştirmede yeniyseniz, bunun çalışması için UIDelegate'i de yetkilendirmeniz gerektiğini belirtmek gerekir.

Bunun gibi bir şey:

self.webView?.UIDelegate = self

Yani değişiklik yapmanız gereken üç yer var.


Kodunuzu yazın, bu:self.webView.UIDelegate = self
Henrik Petterson

Örtülü olup olmadığından emin değilim, ancak bu kod satırının iOS 10'da çalışması ViewControlleriçin devralmanız gerekir WKUIDelegate. yaniclass ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
ltrainpr

4

Ayrıca başka bir görünüm denetleyicisine basabilir veya yeni bir sekme vb. Açabilirsiniz:

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
}

Ayarlamak gerekli vc.urlmi? Ayarlamıyorum ve web görünümü düzgün yükleniyor. Ayrıca, benim deneyim sadece görmenin am createWebViewWithConfigurationçağrılan navigationAction.targetFrameolduğunu nil. Bunun doğru olmayacağı bir senaryo tarif edebilir misiniz?
Mason G. Zhwiti

@ MasonG.Zhwiti Geçen sonbaharda bir proje için aktif olarak WKWebViews kullanıyordum, ancak o zamandan beri onlarla hiçbir şey yapmadım - bu yüzden sorunuzu gerçekten cevaplayamıyorum. Yukarıdakileri yayınladığımda işe yaradı. Yine de vc.url'yi ayarlamadan nasıl çalıştığını anlayamıyorum.
David H

Bence bu işe yaramıyor çünkü oluşturduğunuz web görünümünü döndürüyorsunuz ve ardından (tahmin ediyorum) sizden oluşturmanızı istediği her şey, söz konusu URL'yi yüklemek için web görünümünü kullanmakla ilgileniyor.
Mason G. Zhwiti

3

Dayanarak alyan Huang cevap

ayrıntılar

  • Xcode Sürüm 10.3 (10G8), Swift 5

Hedefler

  • ile bağlantıları tespit etmek target=“_blank”
  • push mevcut denetleyicide varsa denetleyiciyi webView ile görüntüle navigationController
  • present diğer tüm durumlarda webView ile denetleyiciyi görüntüle

Çözüm

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

Tam örnek

Info.plist

Info.plist aktarım güvenlik ayarınıza ekleyin

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

Film şeritleri

Versiyon 1

görüntü açıklamasını buraya girin

Versiyon 2

görüntü açıklamasını buraya girin


merhaba, facebook ile giriş yaptıktan sonra, benzer şekilde facebook paylaşımı için paylaşım penceresi nasıl açılır? Yeni wkwebview oluşturarak giriş yaptım, şimdi kullanıcı oturum açtı. Şimdi paylaşım penceresi nasıl takip edilir?
Jamshed Alam

Teşekkürler, çözümünüz hayatımı kurtarır :)
Samrat Pramanik

2

Bu benim için çalıştı:

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

Gördüğünüz gibi, burada yaptığımız şey sadece webViewyeni url ile yeni bir url açmak ve kapatılma olasılığını kontrol etmektir, sadece second webviewilkinde görüntülenecek bir yanıt almanız gerekiyorsa .


1

Sadece kullanarak çözülemeyen bazı sorunlarla karşılaştım webView.load(navigationAction.request). Bu yüzden yapmak için yeni bir webView kullanıyorum ve gayet iyi çalışıyor.

//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)) }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.