WKWebView im Interface Builder

95

Es scheint, dass die IB-Objektvorlagen in XCode 6 Beta immer noch Objekte im alten Stil erstellen (UIWebView für iOS und WebView für OSX). Hoffentlich wird Apple sie für das moderne WebKit aktualisieren, aber was ist bis dahin der beste Weg, um WKWebViews in Interface Builder zu erstellen? Sollte ich eine Basisansicht (UIView oder NSView) erstellen und ihren Typ WKWebView zuweisen? Die meisten Beispiele, die ich online finde, fügen es programmgesteuert einer Containeransicht hinzu. ist das aus irgendeinem Grund besser?

Adam Fox
quelle
3
Dies ist immer noch ein offener Fehler: lists.webkit.org/pipermail/webkit-unassigned/2014-September/…
David H
4
Ich verwende Xcode 7.2 und sehe WKWebView nicht in der Objektbibliothek. Ist es noch nicht verfügbar?
user3731622
10
Immer noch nicht in Xcode 8 vorhanden.
Ryan Ballantyne
1
Xcode 9.0.1 unterstützt jetzt WKWebView in IB. Alle Antworten hier sind jetzt veraltet.
smileBot
1
@smileBot Die neue Version von Xcode verfügt zwar über WKWebView, erfordert jedoch die Ausrichtung auf iOS 11+. crx_au Antwort funktioniert am besten -> stackoverflow.com/a/40118654/757503
mikemike396

Antworten:

70

Sie haben Recht - es scheint nicht zu funktionieren. Wenn Sie in die Überschriften schauen, sehen Sie:

- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;

was bedeutet, dass Sie keine von einer Feder instanziieren können.

Sie müssen dies manuell in viewDidLoad oder loadView tun.

EricS
quelle
Hoffentlich werden sie das irgendwann ändern, aber ich nehme an, es ist keine große Sache. Johan hat mich auf das WWDC-Video zurückgeführt, und selbst sie instanziieren im Code.
Adam Fox
3
Auf der positiven Seite können Sie UIWebView in iOS 7 und WKWebView in iOS 8 verwenden.
EricS
Nach dieser Antwort können Sie diese Methode in einer Unterklasse von WKWebView überschreiben und dann im Interface Builder verwenden. Aber ohne super.initWithCoder. Lassen Sie uns testen! :)
Zarghol
1
Nach einem persönlichen Test: Sie können nicht ... "Kann 'init', das als nicht verfügbar markiert wurde, nicht überschreiben" schade ...
zarghol
2
Eine sinnvolle Sache könnte darin bestehen, eine UIView-Unteransicht namens MyWebView zu erstellen, die entweder eine WKWebView oder eine UIWebView als Unteransicht enthält, die zur Laufzeit in initWithCoder festgelegt wird. Anschließend können Sie MyWebView-Ansichten in IB erstellen. Wenn Sie Swift verwenden, können Sie sogar Eigenschaften hinzufügen, die in IB mit dem Schlüsselwort IBInspectable bearbeitet werden können.
EricS
65

Wie bereits von einigen erwähnt, ist WKWebView ab Xcode 6.4 im Interface Builder immer noch nicht verfügbar. Es ist jedoch sehr einfach, sie per Code hinzuzufügen.

Ich verwende dies nur in meinem ViewController. Interface Builder überspringen

import UIKit
import WebKit

class ViewController: UIViewController {

    private var webView: WKWebView?

    override func loadView() {
        webView = WKWebView()

        //If you want to implement the delegate
        //webView?.navigationDelegate = self

        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if let url = URL(string: "https://google.com") {
            let req = URLRequest(url: url)
            webView?.load(req)
        }
    }
}
Johan
quelle
13
Diese Frage bezieht sich speziell auf Interface Builder, daher ist diese Antwort nicht sehr hilfreich.
Steve Landey
5
Du hast recht. Ich hätte die Antwort mit "Sie können WKWebView nicht aus IB erstellen" beginnen :) Aber ich schaue mir das Sitzungsvideo "Einführung in die moderne WebKit-API" von WWDC an und sie verwenden Xcode, also denke ich, dass dies nur etwas ist, was nicht " Derzeit nicht verfügbar.
Johan
1
Habe gerade das Video noch einmal ausgecheckt und sie instanziieren ihre WKWebView im Code. Es ist ungefähr um 17:20 Uhr im Video.
Adam Fox
3
Wie wird eine Endlosschleife erstellt? Dies geht aus der Beschreibung von loadView in der iOS-Dokumentation hervor. "Der Ansichtscontroller ruft diese Methode auf, wenn seine Ansichtseigenschaft angefordert wird, aber derzeit Null ist."
Johan
2
Das Referenzieren im self.view InnerenloadView()führt zu einer unendlichen Rekursion. Das Festlegen der Ansicht ist dagegen nicht nur zulässig, sondern auch erforderlich (manuell oder durch Verketten ansuper. Andernfalls wird sie so lange aufgerufen, wie die Ansicht angezeigt wirdnil).
Nicolas Miari
29

Info.plist

Fügen Sie Ihre Info.plist-Transportsicherheitseinstellung hinzu

 <key>NSAppTransportSecurity</key>
 <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
 </dict>

Xcode 9.1+

Interface Builder verwenden

Sie finden das WKWebView-Element in der Objektbibliothek.

Geben Sie hier die Bildbeschreibung ein

Fügen Sie die Ansicht programmgesteuert mit Swift 5 hinzu

let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
view.addSubview(webView)
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

Ansicht programmgesteuert mit Swift 5 hinzufügen (vollständiges Beispiel)

import UIKit
import WebKit

class ViewController: UIViewController {

    private weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        initWebView()
        webView.loadPage(address: "http://apple.com")
    }

    private func initWebView() {
        let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
        view.addSubview(webView)
        self.webView = webView
        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 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)
    }
}
Wassili Bodnarchuk
quelle
Es ist kein guter Vorschlag, eine neue Ansicht im Initialisierer für zuzuweisen WebView. crx_au Antwort ist überlegen
Ilias Karim
Ich habe keine andere Sache gefunden, die funktioniert !! Also ... wie ILI4S sagte, ist es vielleicht kein guter Vorschlag, ich weiß nicht, ob es ist oder nicht, aber es funktioniert richtig! Danke Mann, du hast meinen Tag gerettet !! :)
Jorge Cordero
20

Mit Xcode 8 ist dies jetzt möglich, aber die Mittel, um dies zu erreichen, sind gelinde gesagt ein wenig hackig. Aber hey, eine funktionierende Lösung ist eine funktionierende Lösung, oder? Lassen Sie mich erklären.

WKWebViews initWithCoder: wird nicht mehr als "NS_UNAVAILABLE" bezeichnet. Es sieht jetzt wie unten gezeigt aus.

- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

Beginnen Sie mit der Unterklasse von WKWebView und überschreiben Sie initWithCoder. Anstatt super initWithCoder aufzurufen, müssen Sie eine andere init-Methode verwenden, z. B. initWithFrame: configuration:. Kurzes Beispiel unten.

- (instancetype)initWithCoder:(NSCoder *)coder
{
    // An initial frame for initialization must be set, but it will be overridden 
    // below by the autolayout constraints set in interface builder. 
    CGRect frame = [[UIScreen mainScreen] bounds];
    WKWebViewConfiguration *myConfiguration = [WKWebViewConfiguration new];

    // Set any configuration parameters here, e.g.
    // myConfiguration.dataDetectorTypes = WKDataDetectorTypeAll; 

    self = [super initWithFrame:frame configuration:myConfiguration];

    // Apply constraints from interface builder.
    self.translatesAutoresizingMaskIntoConstraints = NO;

    return self;
}

Verwenden Sie in Ihrem Storyboard eine UIView und geben Sie ihr eine benutzerdefinierte Klasse Ihrer neuen Unterklasse. Der Rest ist wie gewohnt (Festlegen von Einschränkungen für das automatische Layout, Verknüpfen der Ansicht mit einer Steckdose in einem Controller usw.).

Schließlich skaliert WKWebView den Inhalt anders als UIWebView. Viele Leute werden wahrscheinlich den einfachen Ratschlägen in Unterdrücken von WKWebView folgen wollen, indem sie Inhalte skalieren, um sie mit der gleichen Vergrößerung wie UIWebView zu rendern , damit WKWebView das UIWebView-Verhalten in dieser Hinsicht genauer verfolgt.

crx_au
quelle
2
es sollte auch lesen, self = [super initWithFrame:myFrame configuration:myConfiguration];wenn Sie Einschränkungen verwenden, vergessen Sie nicht zu setzenself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66
Anstatt die Grenzen des Hauptbildschirms als Platzhalterrahmen zu verwenden, können Sie auch CGRectZero verwenden und sich Code sparen.
Ilias Karim
Schöne Lösung. Funktioniert gut.
Rayfleck
Funktioniert einwandfrei! Eine gute Lösung, um iOS 11 nicht als Ziel zu verwenden, um WKWebView-Einschränkungen im Storyboard zu erhalten.
mikemike396
20

Hier ist eine einfache Swift 3-Version, die auf der hervorragenden Antwort von crx_au basiert .

import WebKit

class WKWebView_IBWrapper: WKWebView {
    required convenience init?(coder: NSCoder) {
        let config = WKWebViewConfiguration()
        //config.suppressesIncrementalRendering = true //any custom config you want to add
        self.init(frame: .zero, configuration: config)
        self.translatesAutoresizingMaskIntoConstraints = false
    }
}

Erstellen Sie eine UIView in Interface Builder, weisen Sie Ihre Einschränkungen zu und weisen Sie sie WKWebView_IBWrapperwie folgt als benutzerdefinierte Klasse zu:

Dienstprogramme -> Registerkarte Identitätsinspektor [1]

Gamma
quelle
Ausgezeichnete Antwort
Amr Hossam
6

Wenn dieses Problem in neueren Versionen von Xcode, z. B. Version 9.2 +, weiterhin auftritt, importieren Sie einfach Webkit in Ihren ViewController:

#import <WebKit/WebKit.h>
  1. Vor dem Fix: Geben Sie hier die Bildbeschreibung ein

  2. Nach dem Fix:

Geben Sie hier die Bildbeschreibung ein

MrDEV
quelle
4

Dies ist jetzt anscheinend in Xcode 9b4 behoben. In den Versionshinweisen heißt es: "WKWebView ist in der iOS-Objektbibliothek verfügbar."

Ich habe nicht genauer nachgesehen, ob iOS 11 erforderlich oder abwärtskompatibel ist.

EricS
quelle
Ich kann bestätigen, dass dies funktioniert! Hurra! Es funktioniert auch in MacOS-Storyboards (zumindest für Apps für MacOS 10.13+).
Clifton Labrum
1

Sie können eine WKWebView in IB seit Xcode 9 instanziieren und konfigurieren, ohne dies im Code tun zu müssen. Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass Ihr Bereitstellungsziel höher als iOS 10 sein muss, da sonst ein Fehler beim Kompilieren angezeigt wird.

Geben Sie hier die Bildbeschreibung ein

atineoSE
quelle
0

In XCode Version 9.0.1 ist WKWebView im Interface Builder verfügbar.

ManuelMB
quelle
0

Ich habe WebKit verlinkt, jetzt funktioniert es!

Beispiel

Tagesanbruch zhou
quelle
0

Ich bin mir nicht sicher, ob dies hilft, aber ich habe das Problem für mich gelöst, indem ich das WebKit-Framework für das Ziel aufgenommen habe. Betten Sie es nicht ein, sondern verknüpfen Sie einfach die Referenz. Ich verwende das WebView-Objekt immer noch in IB und lege es auf dem ViewController ab, in den ich es einbette, und ich hatte nie ein Problem ...

Ich habe jetzt an 4 WKWebView MacOS-Projekten gearbeitet und das WebView hat in jedem Projekt ordnungsgemäß funktioniert.

ranTrek
quelle
-14

Das hat bei mir in Xcode 7.2 funktioniert ...

Fügen Sie zuerst die Webansicht als UIWebView-Ausgang im Storyboard / IB hinzu. Dadurch erhalten Sie eine Eigenschaft wie diese:

@property (weak, nonatomic) IBOutlet UIWebView *webView;

Bearbeiten Sie dann einfach Ihren Code, um ihn in eine WKWebView zu ändern.

@property (weak, nonatomic) IBOutlet WKWebView *webView;

Sie sollten die benutzerdefinierte Klasse auch im Identitätsinspektor in WKWebView ändern.

Pat McG
quelle
Ich habe dies mit einem OS X-Projekt versucht - das funktioniert nicht, daher muss es ein Sonderfall für iOS sein.
Henrikstroem
2
Was Sie tun, ist wie Typcast. Der Typ von webView kann NICHT geändert werden.
DawnSong