WKWebView no Interface Builder


95

Parece que os modelos de objeto IB no XCode 6 beta ainda estão criando objetos de estilo antigo (UIWebView para iOS e WebView para OSX). Esperançosamente, a Apple irá atualizá-los para o WebKit moderno, mas até então, qual é a melhor maneira de criar WKWebViews no Interface Builder? Devo criar uma exibição básica (UIView ou NSView) e atribuir seu tipo a WKWebView? A maioria dos exemplos que encontro online o adiciona a uma visualização de contêiner de forma programática; isso é melhor por algum motivo?



4
Estou usando o Xcode 7.2, não vejo WKWebView na biblioteca de objetos. Ainda não está disponível?
user3731622

10
Ainda não está presente no Xcode 8.
Ryan Ballantyne

1
O Xcode 9.0.1 agora oferece suporte a WKWebView em IB. Todas as respostas aqui estão obsoletas.
smileBot

1
@smileBot A nova versão do Xcode tem WKWebView, mas requer que você direcione o iOS 11+. a resposta crx_au funciona melhor -> stackoverflow.com/a/40118654/757503
mikemike396

Respostas:


70

Você está correto - não parece funcionar. Se você olhar nos cabeçalhos, verá:

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

o que implica que você não pode instanciar um de um bico.

Você terá que fazer isso manualmente em viewDidLoad ou loadView.


Espero que eles mudem isso em algum momento, mas acho que não é grande coisa. Johan me apontou de volta para o vídeo WWDC, e até mesmo eles estão instanciando em código.
Adam Fox de

3
No lado positivo, fazer isso em código permitirá que você use UIWebView no iOS 7 e WKWebView no iOS 8.
EricS

Bem, depois dessa resposta, acho que você pode substituir esse método em uma subclasse de WKWebView e, em seguida, usá-lo no construtor de interface .. mas sem super.initWithCoder .. vamos testar! :)
zarghol

1
Depois de um teste pessoal: você não pode ... "Não é possível substituir 'init' que foi marcado como indisponível" muito ruim ...
zarghol

2
Uma coisa razoável a fazer pode ser criar uma subvisualização UIView chamada MyWebView que tem um WKWebView ou um UIWebView como subvisualização, determinado no tempo de execução em initWithCoder. Então você pode criar visualizações MyWebView no IB. Se você estiver usando o Swift, você pode até adicionar propriedades que podem ser editadas no IB usando a palavra-chave IBInspectable.
EricS

65

Como apontado por alguns, a partir do Xcode 6.4, WKWebView ainda não está disponível no Interface Builder. No entanto, é muito fácil adicioná-los via código.

Estou apenas usando isso no meu ViewController. Skipping Interface builder

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

13
Esta pergunta é especificamente sobre o Interface Builder, portanto, esta resposta não é muito útil.
Steve Landey

5
Você está certo. Eu deveria ter começado a resposta com “Você não pode criar WKWebView do IB" :) Mas eu assisto ao vídeo da sessão “Apresentando a API Modern WebKit" da WWDC e eles estão usando o Xcode, então acho que isso é apenas algo que não é t disponível para nós no momento.
Johan

1
Acabei de conferir o vídeo novamente e eles estão instanciando seu WKWebView em código. Está em torno da marca de 17:20 no vídeo.
Adam Fox de

3
Como isso criará um loop infinito? Isso é da descrição de loadView na documentação do iOS. "O controlador de visualização chama este método quando sua propriedade de visualização é solicitada, mas atualmente é nula."
Johan

2
Referenciar self.view internamenteloadView()é o que leva à recursão infinita. Definir a visualização, por outro lado, não é apenas permitido, mas também obrigatório (manualmente ou por encadeamentosuper. Caso contrário, continuará sendo chamado enquanto a visualização fornil).
Nicolas Miari

29

Info.plist

adicione em sua configuração de segurança de transporte Info.plist

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

Xcode 9.1+

Usando o construtor de interface

Você pode encontrar o elemento WKWebView na biblioteca de objetos.

insira a descrição da imagem aqui

Adicionar visualização programaticamente com 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

Adicionar visualização programaticamente com Swift 5 (amostra completa)

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

Não é uma boa sugestão alocar uma nova visão no inicializador para WebView. A resposta de crx_au é superior
Ilias Karim

Não encontrei nenhuma outra coisa que funcione !! Então ... como o ILI4S falou talvez não seja uma boa sugestão, não sei se é ou não, mas funciona bem! Obrigado cara, você salvou meu dia !! :)
Jorge Cordero

20

Com o Xcode 8 isso agora é possível, mas o meio de alcançá-lo é um pouco hacky, para dizer o mínimo. Mas hey, uma solução funcional é uma solução funcional, certo? Deixe-me explicar.

InitWithCoder de WKWebView: não está mais anotado como "NS_UNAVAILABLE". Agora se parece com o mostrado abaixo.

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

Comece criando uma subclasse de WKWebView e substitua initWithCoder. Em vez de chamar super initWithCoder, você precisará usar um método init diferente, como initWithFrame: configuration :. Exemplo rápido abaixo.

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

Em seu Storyboard, use um UIView e dê a ele uma classe personalizada de sua nova subclasse. O resto é business as usual (definir restrições de layout automático, vincular a visualização a uma saída em um controlador, etc.).

Finalmente, WKWebView dimensiona o conteúdo de maneira diferente para UIWebView. Muitas pessoas provavelmente vão querer seguir o conselho simples em Suprimir WKWebView do escalonamento do conteúdo para renderizar na mesma ampliação que o UIWebView faz para fazer com que o WKWebView siga mais de perto o comportamento do UIWebView a esse respeito.


2
deve ler self = [super initWithFrame:myFrame configuration:myConfiguration];também se você usar restrições, não se esqueça de definirself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66

Em vez de usar os limites da tela principal como um espaço reservado, você também pode usar o CGRectZero e salvar algum código.
Ilias Karim

Ótima solução. Funciona bem.
Rayfleck de

Funciona perfeitamente! Boa correção para não ter que direcionar o iOS 11 para obter restrições WKWebView no storyboard.
mikemike396

20

Aqui está uma versão simples do Swift 3 baseada na excelente resposta de 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
    }
}

Crie um UIView no Interface Builder, atribua suas restrições e atribua-o WKWebView_IBWrappercomo uma classe personalizada, assim:

Utilitários -> Guia Inspetor de identidade [1]


Excelente resposta
Amr Hossam

6

Se você ainda enfrenta esse problema nas versões recentes do Xcode, ou seja, v9.2 +, basta importar o Webkit para o seu ViewController:

#import <WebKit/WebKit.h>
  1. Antes da correção: insira a descrição da imagem aqui

  2. Após a correção:

insira a descrição da imagem aqui


4

Isso agora está aparentemente corrigido no Xcode 9b4. As notas de lançamento dizem "WKWebView está disponível na biblioteca de objetos iOS."

Não olhei mais fundo para ver se ele requer iOS 11 ou é compatível com versões anteriores.


Posso confirmar que isso funciona! Hooray! Ele também funciona em storyboards do macOS (pelo menos para aplicativos voltados para o macOS 10.13+).
Clifton Labrum

1

Você pode instanciar e configurar um WKWebView no IB desde o Xcode 9, sem necessidade de fazer isso no código. insira a descrição da imagem aqui

Observe que seu destino de implantação deve ser superior ao iOS 10 ou você obterá um erro de tempo de compilação.

insira a descrição da imagem aqui


0

No XCode Versão 9.0.1, WKWebView está disponível no Interface Builder.



0

Não tenho certeza se isso ajuda, mas resolvi o problema para mim incluindo a estrutura do WebKit para o destino. Não incorpore, apenas vincule a referência. Eu ainda uso o objeto WebView no IB e coloco-o no ViewController no qual estou incorporando e nunca tive um problema ...

Eu trabalhei em 4 projetos WKWebView MacOS agora e o WebView funcionou corretamente em cada projeto.


-14

Isso funcionou para mim no Xcode 7.2 ...

Primeiro adicione a visualização da web como uma saída UIWebView no storyboard / IB. Isso lhe dará uma propriedade como esta:

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

Em seguida, edite o código para alterá-lo para WKWebView.

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

Você também deve alterar a classe personalizada para WKWebView no inspetor de identidade.


Tentei fazer isso com um projeto OS X - que não funciona, então deve ser um caso especial para iOS.
Henrikstroem

2
O que você faz é como um tipo de elenco. Ele NÃO pode alterar o tipo do webView.
DawnSong
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.