WKWebView w programie Interface Builder

95

Wygląda na to, że szablony obiektów IB w XCode 6 beta nadal tworzą obiekty w starym stylu (UIWebView dla iOS i WebView dla OSX). Mam nadzieję, że Apple zaktualizuje je pod kątem nowoczesnego WebKit, ale do tego czasu, jaki jest najlepszy sposób tworzenia WKWebViews w Interface Builder? Czy powinienem utworzyć widok podstawowy (UIView lub NSView) i przypisać jego typ do WKWebView? Większość przykładów, które znajduję w Internecie, dodaje je programowo do widoku kontenera; czy to jest lepsze z jakiegoś powodu?

Adam Fox
źródło
3
To wciąż jest otwarty błąd: lists.webkit.org/pipermail/webkit-unassigned/2014-September/ ...
David H
4
Używam Xcode 7.2, nie widzę WKWebView w bibliotece obiektów. Czy nadal nie jest dostępny?
user3731622
10
Nadal nieobecny w Xcode 8.
Ryan Ballantyne
1
Xcode 9.0.1 obsługuje teraz WKWebView w IB. Wszystkie odpowiedzi tutaj są przestarzałe.
smileBot
1
@smileBot Nowa wersja Xcode ma WKWebView, ale wymaga docelowego systemu iOS 11+. odpowiedź crx_au działa najlepiej -> stackoverflow.com/a/40118654/757503
mikemike396

Odpowiedzi:

70

Masz rację - to nie działa. Jeśli spojrzysz na nagłówki, zobaczysz:

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

co oznacza, że ​​nie można utworzyć instancji z końcówki.

Będziesz musiał to zrobić ręcznie w viewDidLoad lub loadView.

EricS
źródło
Mam nadzieję, że kiedyś to zmienią, ale myślę, że to nic wielkiego. Johan odesłał mnie z powrotem do wideo WWDC, a nawet oni tworzą instancję w kodzie.
Adam Fox
3
Z drugiej strony, zrobienie tego w kodzie pozwoli ci używać UIWebView w iOS 7 i WKWebView w iOS 8.
EricS
Cóż, po tej odpowiedzi myślę, że można przesłonić tę metodę w podklasie WKWebView, a następnie użyć jej w programie do tworzenia interfejsów .. ale bez super.initWithCoder .. przetestujmy! :)
zarghol
1
Po osobistym teście: nie możesz ... "Nie można zastąpić 'init', który został oznaczony jako niedostępny" szkoda ...
zarghol
2
Jedną rozsądną rzeczą do zrobienia może być utworzenie podwidoku UIView o nazwie MyWebView, który ma WKWebView lub UIWebView jako podwidok, określany w czasie wykonywania w initWithCoder. Następnie możesz tworzyć widoki MyWebView w IB. Jeśli używasz Swift, możesz nawet dodać właściwości, które można edytować w IB za pomocą słowa kluczowego IBInspectable.
EricS
65

Jak zauważyli niektórzy, od Xcode 6.4 WKWebView nadal nie jest dostępny w Interface Builder. Jednak bardzo łatwo jest je dodać za pomocą kodu.

Po prostu używam tego w moim ViewController. Pomijanie kreatora interfejsów

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
źródło
13
To pytanie dotyczy szczególnie programu Interface Builder, więc ta odpowiedź nie jest zbyt pomocna.
Steve Landey
5
Masz rację. Powinienem był zacząć odpowiedź od „Nie można utworzyć WKWebView z IB” :) Ale oglądam film z sesji „Wprowadzenie nowoczesnego interfejsu API WebKit” z WWDC i używają Xcode, więc myślę, że to po prostu coś, co nie jest ' w tej chwili dostępne.
Johan
1
Właśnie ponownie obejrzałem wideo i utworzyli instancję swojego WKWebView w kodzie. Jest to około godziny 17:20 na filmie.
Adam Fox
3
W jaki sposób utworzy nieskończoną pętlę? To pochodzi z opisu loadView w dokumentacji iOS. „Kontroler widoku wywołuje tę metodę, gdy żądana jest jego właściwość widoku, ale obecnie ma wartość zero”.
Johan
2
Odniesienie do self.view wnętrzaloadView()prowadzi do nieskończonej rekurencji. Z drugiej strony ustawienie widoku jest nie tylko dozwolone, ale wręcz wymagane (ręcznie lub przez połączenie łańcuchowesuper. W przeciwnym razie będzie wywoływane tak długo, jak widok jestnil).
Nicolas Miari,
29

Info.plist

dodaj swoje ustawienia bezpieczeństwa transportu Info.plist

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

Xcode 9.1+

Korzystanie z konstruktora interfejsu

Element WKWebView można znaleźć w bibliotece obiektów.

wprowadź opis obrazu tutaj

Dodaj widok programowo za pomocą Swift 5

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

Dodaj widok programowo za pomocą Swift 5 (pełna próbka)

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)
    }
}
Wasilij Bodnarczuk
źródło
Przydzielanie nowego widoku w inicjatorze dla platformy nie jest dobrą sugestią WebView. Odpowiedź crx_au jest lepsza
Ilias Karim
Nie znalazłem innej rzeczy, która działa !! Więc ... jak powiedział ILI4S, może to nie jest dobra sugestia, nie wiem, czy tak jest, czy nie, ale działa poprawnie! Dzięki stary, uratowałeś mi dzień !! :)
Jorge Cordero
20

Dzięki Xcode 8 jest to teraz możliwe, ale środki do osiągnięcia tego są co najmniej trochę hakerskie. Ale hej, działające rozwiązanie to działające rozwiązanie, prawda? Pozwól mi wyjaśnić.

WKWebView initWithCoder: nie ma już adnotacji „NS_UNAVAILABLE”. Teraz wygląda tak, jak pokazano poniżej.

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

Zacznij od podklasy WKWebView i zastąp initWithCoder. Zamiast wywoływać super initWithCoder, musisz użyć innej metody init, takiej jak initWithFrame: configuration :. Krótki przykład poniżej.

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

W swoim Storyboard użyj UIView i nadaj mu niestandardową klasę swojej nowej podklasy. Reszta to zwykły biznes (ustawienie ograniczeń automatycznego układu, połączenie widoku z gniazdem w kontrolerze itp.).

Wreszcie WKWebView skaluje zawartość inaczej niż UIWebView. Wiele osób prawdopodobnie będzie chciało postępować zgodnie z prostą radą w Pomijanie WKWebView ze skalowania zawartości w celu renderowania przy takim samym powiększeniu, jak robi to UIWebView, aby WKWebView dokładniej podążał za zachowaniem UIWebView w tym zakresie.

crx_au
źródło
2
należy przeczytać self = [super initWithFrame:myFrame configuration:myConfiguration];również, jeśli używasz ograniczeń, nie zapomnij ustawićself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66
Zamiast używać granic ekranu głównego jako ramki zastępczej, możesz również użyć CGRectZero i zapisać sobie kod.
Ilias Karim
Niezłe rozwiązanie. Działa dobrze.
Rayfleck
Działa bez zarzutu! Niezła poprawka, że ​​nie trzeba kierować reklamy na system iOS 11, aby uzyskać ograniczenia WKWebView w scenorysie.
mikemike396
20

Oto prosta wersja Swift 3 oparta na doskonałej odpowiedzi crx_au .

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

Utwórz UIView w Interface Builder, przypisz swoje ograniczenia i przypisz je WKWebView_IBWrapperjako klasę niestandardową, na przykład:

Narzędzia -> karta Inspektor tożsamości [1]

Gamma
źródło
Doskonała odpowiedź
Amr Hossam
6

Jeśli nadal napotykasz ten problem w ostatnich wersjach Xcode, tj. W wersji 9.2 +, po prostu zaimportuj Webkit do swojego ViewController:

#import <WebKit/WebKit.h>
  1. Przed naprawą: wprowadź opis obrazu tutaj

  2. Po naprawie:

wprowadź opis obrazu tutaj

MrDEV
źródło
4

Zostało to najwyraźniej naprawione w Xcode 9b4. W informacjach o wersji jest napisane „WKWebView jest dostępny w bibliotece obiektów iOS”.

Nie szukałem głębiej, aby sprawdzić, czy wymaga iOS 11, czy jest jeszcze kompatybilny wstecz.

EricS
źródło
Mogę potwierdzić, że to działa! Brawo! Działa również w scenorysach macOS (przynajmniej w aplikacjach przeznaczonych dla macOS 10.13+).
Clifton Labrum
1

Możesz utworzyć wystąpienie i skonfigurować WKWebView w IB od Xcode 9, nie musisz robić tego w kodzie. wprowadź opis obrazu tutaj

Należy pamiętać, że cel wdrożenia musi być wyższy niż iOS 10, w przeciwnym razie wystąpi błąd w czasie kompilacji.

wprowadź opis obrazu tutaj

atineoSE
źródło
0

W XCode w wersji 9.0.1 WKWebView jest dostępny w Interface Builder.

ManuelMB
źródło
0

Połączyłem WebKit, teraz działa!

przykład

świt zhou
źródło
0

Nie jestem pewien, czy to pomoże, ale rozwiązałem problem, dołączając framework WebKit do celu. Nie osadzaj go, tylko połącz odnośnik. Nadal używam obiektu WebView w IB i upuszczam go na ViewController, w którym go osadzam i nigdy nie miałem problemu ...

Pracowałem teraz nad 4 projektami WKWebView MacOS i WebView działał poprawnie w każdym projekcie.

ranTrek
źródło
-14

To działało dla mnie w Xcode 7.2 ...

Najpierw dodaj widok sieci Web jako gniazdo UIWebView w serii ujęć / IB. W ten sposób uzyskasz taką właściwość:

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

Następnie po prostu edytuj kod, aby zmienić go na WKWebView.

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

Należy również zmienić klasę niestandardową na WKWebView w Inspektorze tożsamości.

Pat McG
źródło
Próbowałem tego z projektem OS X - to nie działa, więc musi to być specjalny przypadek dla iOS.
henrikstroem
2
To, co robisz, jest jak typowanie. NIE może w ogóle zmienić typu webView.
DawnSong