WKWebView dans Interface Builder

95

Il semble que les modèles d'objets IB dans XCode 6 beta créent toujours des objets à l'ancienne (UIWebView pour iOS et WebView pour OSX). Espérons qu'Apple les mettra à jour pour le WebKit moderne, mais d'ici là, quelle est la meilleure façon de créer des WKWebViews dans Interface Builder? Dois-je créer une vue de base (UIView ou NSView) et attribuer son type à WKWebView? La plupart des exemples que je trouve en ligne l'ajoutent à une vue de conteneur par programmation; est-ce mieux pour une raison quelconque?

Adam Fox
la source
3
Ceci est toujours un bogue ouvert: lists.webkit.org/pipermail/webkit-unassigned/2014-September/…
David H
4
J'utilise Xcode 7.2, je ne vois pas WKWebView dans la bibliothèque d'objets. N'est-il toujours pas disponible?
user3731622
10
Toujours pas présent dans Xcode 8.
Ryan Ballantyne
1
Xcode 9.0.1 prend désormais en charge WKWebView dans IB. Toutes les réponses ici sont désormais obsolètes.
smileBot
1
@smileBot La nouvelle version de Xcode a WKWebView mais il vous oblige à cibler iOS 11+. La réponse crx_au fonctionne le mieux -> stackoverflow.com/a/40118654/757503
mikemike396

Réponses:

70

Vous avez raison - cela ne semble pas fonctionner. Si vous regardez dans les en-têtes, vous verrez:

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

ce qui implique que vous ne pouvez pas en instancier un à partir d'une pointe.

Vous devrez le faire à la main dans viewDidLoad ou loadView.

EricS
la source
J'espère qu'ils changeront cela à un moment donné, mais je suppose que ce n'est pas grave. Johan m'a renvoyé à la vidéo de la WWDC, et même ils sont instanciés dans le code.
Adam Fox
3
Du côté positif, le faire dans le code vous permettra d'utiliser UIWebView sous iOS 7 et WKWebView sous iOS 8.
EricS
Eh bien après cette réponse, je pense que vous pouvez remplacer cette méthode dans une sous-classe de WKWebView et l'utiliser ensuite dans le constructeur d'interface .. mais sans super.initWithCoder .. testons! :)
zarghol
1
Après un test personnel: vous ne pouvez pas ... "Impossible de remplacer 'init' qui a été marqué comme indisponible" dommage ...
zarghol
2
Une chose raisonnable à faire pourrait être de créer une sous-vue UIView appelée MyWebView qui a soit un WKWebView ou une UIWebView comme sous-vue, déterminée au moment de l'exécution dans initWithCoder. Ensuite, vous pouvez créer des vues MyWebView dans IB. Si vous utilisez Swift, vous pouvez même ajouter des propriétés qui peuvent être modifiées dans IB à l'aide du mot clé IBInspectable.
EricS
65

Comme certains l'ont souligné, à partir de Xcode 6.4, WKWebView n'est toujours pas disponible sur Interface Builder. Cependant, il est très facile de les ajouter via le code.

J'utilise juste ceci dans mon ViewController. Sauter le générateur d'interface

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
la source
13
Cette question concerne spécifiquement Interface Builder, donc cette réponse n'est pas très utile.
Steve Landey
5
Vous avez raison. J'aurais dû commencer la réponse par "Vous ne pouvez pas créer WKWebView à partir d'IB" :) Mais je regarde la vidéo de session "Présentation de l'API WebKit moderne" de WWDC et ils utilisent Xcode donc je suppose que c'est juste quelque chose qui n'est pas t disponible pour nous pour le moment.
Johan
1
Je viens de regarder à nouveau la vidéo et ils instancient leur WKWebView dans le code. C'est autour de la marque 17:20 dans la vidéo.
Adam Fox
3
Comment va-t-il créer une boucle infinie? Cela provient de la description de loadView dans la documentation iOS. "Le contrôleur de vue appelle cette méthode lorsque sa propriété de vue est demandée mais est actuellement nulle."
Johan
2
Le référencement à l' self.view intérieurloadView()est ce qui conduit à une récursivité infinie. La définition de la vue, en revanche, est non seulement autorisée mais en fait obligatoire (manuellement ou par chaînagesuper. Sinon, elle continuera à être appelée tant que la vue le seranil).
Nicolas Miari
29

Info.plist

ajoutez votre paramètre de sécurité de transport Info.plist

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

Xcode 9.1+

Utilisation du générateur d'interface

Vous pouvez trouver l'élément WKWebView dans la bibliothèque d'objets.

entrez la description de l'image ici

Ajouter une vue par programmation avec 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

Ajouter une vue par programmation avec Swift 5 (échantillon complet)

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)
    }
}
Vasily Bodnarchuk
la source
Ce n'est pas une bonne suggestion d'allouer une nouvelle vue dans l'initialiseur pour WebView. La réponse de crx_au est supérieure
Ilias Karim
Je n'ai trouvé aucune autre chose qui fonctionne !! Donc ... comme ILI4S l'a dit, ce n'est peut-être pas une bonne suggestion, je ne sais pas si c'est ou non, mais fonctionne correctement! Merci mec, vous avez sauvé ma journée !! :)
Jorge Cordero
20

Avec Xcode 8, c'est désormais possible, mais les moyens d'y parvenir sont pour le moins un peu piratés. Mais bon, une solution de travail est une solution de travail, non? Laisse-moi expliquer.

InitWithCoder de WKWebView: n'est plus annoté comme "NS_UNAVAILABLE". Il ressemble maintenant à l'illustration ci-dessous.

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

Commencez par sous-classer WKWebView et remplacez initWithCoder. Au lieu d'appeler super initWithCoder, vous devrez utiliser une méthode init différente, telle que initWithFrame: configuration :. Exemple rapide ci-dessous.

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

Dans votre Storyboard, utilisez un UIView et donnez-lui une classe personnalisée de votre nouvelle sous-classe. Le reste est normal (définition de contraintes de mise en page automatique, liaison de la vue à une prise dans un contrôleur, etc.).

Enfin, WKWebView met à l'échelle le contenu différemment de UIWebView. De nombreuses personnes voudront probablement suivre le conseil simple de Supprimer WKWebView de la mise à l'échelle du contenu pour le rendre au même grossissement que UIWebView pour que WKWebView suive de plus près le comportement d'UIWebView à cet égard.

crx_au
la source
2
il devrait lire self = [super initWithFrame:myFrame configuration:myConfiguration];aussi si vous utilisez des contraintes, n'oubliez pas de définirself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66
Plutôt que d'utiliser les limites de l'écran principal comme cadre d'espace réservé, vous pouvez également utiliser CGRectZero et enregistrer vous-même du code.
Ilias Karim
Belle solution. Fonctionne bien.
Rayfleck
Fonctionne parfaitement! Correctif intéressant pour ne pas avoir à cibler iOS 11 pour obtenir les contraintes WKWebView dans le storyboard.
mikemike396
20

Voici une version simple de Swift 3 basée sur l'excellente réponse 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
    }
}

Créez un UIView dans Interface Builder, attribuez vos contraintes et affectez-le en WKWebView_IBWrappertant que classe personnalisée, comme ceci:

Utilitaires -> Onglet Inspecteur d’identité [1]

Gamma
la source
Excellente réponse
Amr Hossam
6

Si vous rencontrez toujours ce problème dans les versions récentes de Xcode, c'est-à-dire v9.2 +, importez simplement Webkit dans votre ViewController:

#import <WebKit/WebKit.h>
  1. Avant le correctif: entrez la description de l'image ici

  2. Après le correctif:

entrez la description de l'image ici

MrDEV
la source
4

Ceci est maintenant apparemment corrigé dans Xcode 9b4. Les notes de publication indiquent que «WKWebView est disponible dans la bibliothèque d'objets iOS».

Je n'ai pas cherché plus en profondeur pour voir s'il nécessite iOS 11 ou s'il est encore rétrocompatible.

EricS
la source
Je peux confirmer que cela fonctionne! Hourra! Cela fonctionne également dans les storyboards macOS (au moins pour les applications ciblant macOS 10.13+).
Clifton Labrum
1

Vous pouvez instancier et configurer un WKWebView dans IB depuis Xcode 9, pas besoin de le faire dans le code. entrez la description de l'image ici

Notez que votre cible de déploiement doit être supérieure à iOS 10, sinon vous obtiendrez une erreur de compilation.

entrez la description de l'image ici

atineoSE
la source
0

Dans XCode version 9.0.1, WKWebView est disponible sur Interface Builder.

ManuelMB
la source
0

J'ai lié WebKit, maintenant ça marche!

exemple

Zhou au lever du jour
la source
0

Je ne sais pas si cela aide, mais j'ai résolu le problème pour moi en incluant le framework WebKit pour la cible. Ne pas l'intégrer, lier simplement la référence. J'utilise toujours l'objet WebView dans IB et le dépose sur le ViewController dans lequel je l'intègre et je n'ai jamais eu de problème ...

J'ai travaillé sur 4 projets WKWebView MacOS maintenant et le WebView a fonctionné correctement dans chaque projet.

ranTrek
la source
-14

Cela a fonctionné pour moi dans Xcode 7.2 ...

Ajoutez d'abord la vue Web en tant que sortie UIWebView dans le storyboard / IB. Cela vous donnera une propriété comme celle-ci:

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

Ensuite, modifiez simplement votre code pour le changer en WKWebView.

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

Vous devez également modifier la classe personnalisée en WKWebView dans l'inspecteur d'identité.

Pat McG
la source
J'ai essayé cela avec un projet OS X - cela ne fonctionne pas, donc ce doit être un cas particulier pour iOS.
henrikstroem
2
Ce que vous faites est juste comme la fonte de caractères. Il ne peut PAS changer du tout le type de la vue Web.
DawnSong