WKWebView в Интерфейсном Разработчике

95

Похоже, что шаблоны объектов IB в бета-версии XCode 6 все еще создают объекты старого стиля (UIWebView для iOS и WebView для OSX). Надеюсь, Apple обновит их до современного WebKit, но до тех пор, как лучше всего создавать WKWebView в Interface Builder? Должен ли я создать базовое представление (UIView или NSView) и присвоить его тип WKWebView? Большинство примеров, которые я нахожу в Интернете, добавляют его в представление контейнера программно; это лучше по какой-то причине?

Адам Фокс
источник
3
Это все еще открытая ошибка: lists.webkit.org/pipermail/webkit-unassigned/2014-September/…
Дэвид Х
4
Я использую Xcode 7.2, я не вижу WKWebView в библиотеке объектов. Это все еще недоступно?
user3731622
10
По-прежнему отсутствует в Xcode 8.
Райан Баллантайн
1
Xcode 9.0.1 теперь поддерживает WKWebView в IB. Все ответы здесь устарели.
smileBot 09
1
@smileBot В новой версии Xcode есть WKWebView, но он требует, чтобы вы ориентировались на iOS 11+. crx_au ответ работает лучше всего -> stackoverflow.com/a/40118654/757503
mikemike396 01

Ответы:

70

Вы правы - похоже, это не работает. Если вы посмотрите в заголовки, вы увидите:

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

что означает, что вы не можете создать экземпляр из пера.

Вам нужно будет сделать это вручную в viewDidLoad или loadView.

EricS
источник
Надеюсь, в какой-то момент они это изменят, но я полагаю, что это не имеет большого значения. Йохан снова указал мне на видео WWDC, и даже они создают экземпляр в коде.
Adam Fox
3
С другой стороны, выполнение этого в коде позволит вам использовать UIWebView в iOS 7 и WKWebView в iOS 8.
EricS
После этого ответа, я думаю, вы можете переопределить этот метод в подклассе WKWebView, а затем использовать его в построителе интерфейса ... но без super.initWithCoder ... давайте протестируем! :)
zarghol 09
1
После личного теста: вы не можете ... «Невозможно переопределить 'init', который был отмечен как недоступный», очень плохо ...
zarghol
2
Разумно было бы создать подпредставление UIView под названием MyWebView, которое имеет либо WKWebView, либо UIWebView в качестве подпредставления, определяемого во время выполнения в initWithCoder. Затем вы можете создавать представления MyWebView в IB. Если вы используете Swift, вы даже можете добавлять свойства, которые можно редактировать в IB, используя ключевое слово IBInspectable.
EricS
65

Как отмечают некоторые, начиная с Xcode 6.4, WKWebView все еще недоступен в Interface Builder. Однако их очень легко добавить с помощью кода.

Я просто использую это в своем ViewController. Пропуск построителя интерфейса

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
Этот вопрос касается конкретно Interface Builder, поэтому этот ответ не очень полезен.
Стив Лэнди
5
Ты прав. Я должен был начать ответ со слов «Вы не можете создать WKWebView из IB» :) Но я смотрю сессионное видео «Знакомство с Modern WebKit API» с WWDC, и они используют Xcode, поэтому я предполагаю, что это просто что-то не так. т доступны нам в данный момент.
Johan
1
Только что снова посмотрели видео, и они создают экземпляр своего WKWebView в коде. На видео это примерно 17:20.
Adam Fox
3
Как он создаст бесконечный цикл? Это из описания loadView в документации iOS. «Контроллер представления вызывает этот метод, когда его свойство представления запрашивается, но в настоящее время равно нулю».
Johan
2
Обращение self.view внутрьloadView()приводит к бесконечной рекурсии. С другой стороны, установка представления не только разрешена, но и действительно необходима (вручную или путем привязки кsuper. В противном случае она будет вызываться, пока есть представлениеnil).
Николас Миари
29

Info.plist

добавьте в свой Info.plist настройку безопасности транспорта

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

Xcode 9.1+

Использование конструктора интерфейсов

Вы можете найти элемент WKWebView в библиотеке объектов.

введите описание изображения здесь

Программное добавление представления с помощью 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

Добавить представление программно с помощью Swift 5 (полный пример)

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)
    }
}
Василий Боднарчук
источник
Не рекомендуется выделять новое представление в инициализаторе для WebView. crx_au отвечает превосходно
Ilias Karim
Я не нашел ничего, что работает !! Итак ... как сказал ILI4S, возможно, это не очень хорошее предложение, я не знаю, так оно или нет, но работает правильно! Спасибо, чувак, ты спас мне день !! :)
Хорхе Кордеро
20

С Xcode 8 это теперь возможно, но средства достижения этого, мягко говоря, немного хакерские. Но эй, рабочее решение - это рабочее решение, верно? Позволь мне объяснить.

WKWebView initWithCoder: больше не аннотируется как «NS_UNAVAILABLE». Теперь это выглядит так, как показано ниже.

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

Начните с создания подкласса WKWebView и переопределите initWithCoder. Вместо вызова super initWithCoder вам потребуется использовать другой метод инициализации, например initWithFrame: configuration :. Быстрый пример ниже.

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

В вашей раскадровке используйте UIView и дайте ему собственный класс вашего нового подкласса. Остальное - обычное дело (установка ограничений автоматического макета, привязка представления к выходу в контроллере и т. Д.).

Наконец, WKWebView масштабирует контент иначе, чем UIWebView. Многие люди, вероятно, захотят последовать простому совету в Запретить WKWebView масштабировать контент для рендеринга с тем же увеличением, что и UIWebView, чтобы WKWebView более внимательно следил за поведением UIWebView в этом отношении.

crx_au
источник
2
его также следует прочитать, self = [super initWithFrame:myFrame configuration:myConfiguration];если вы используете ограничения, не забудьте установитьself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66
Вместо того, чтобы использовать границы главного экрана в качестве фрейма-заполнителя, вы также можете использовать CGRectZero и сохранить код.
Ilias Karim
Хорошее решение. Работает хорошо.
Rayfleck
Работает безотказно! Хорошее исправление для того, чтобы не настраивать таргетинг на iOS 11, чтобы получить ограничения WKWebView в раскадровке.
mikemike396 01
20

Вот простая версия Swift 3, основанная на отличном ответе 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
    }
}

Создайте UIView в Интерфейсном Разработчике, назначьте свои ограничения и назначьте его WKWebView_IBWrapperкак настраиваемый класс, например:

Утилиты -> Вкладка "Инспектор идентичности" [1]

Гамма
источник
Отличный ответ
Амр Хоссам
6

Если вы все еще сталкиваетесь с этой проблемой в последних версиях Xcode, то есть v9.2 +, просто импортируйте Webkit в свой ViewController:

#import <WebKit/WebKit.h>
  1. Перед исправлением: введите описание изображения здесь

  2. После исправления:

введите описание изображения здесь

MrDEV
источник
4

Теперь это, по-видимому, исправлено в Xcode 9b4. В примечаниях к выпуску говорится, что «WKWebView доступен в библиотеке объектов iOS».

Я еще не смотрел глубже, чтобы узнать, требуется ли для этого iOS 11 или она обратно совместима.

EricS
источник
Я могу подтвердить, что это работает! Ура! Он также работает в раскадровках macOS (по крайней мере, для приложений, ориентированных на macOS 10.13+).
Clifton
1

Вы можете создать и настроить WKWebView в IB, начиная с Xcode 9, нет необходимости делать это в коде. введите описание изображения здесь

Обратите внимание, что ваша цель развертывания должна быть выше, чем iOS 10, иначе вы получите ошибку времени компиляции.

введите описание изображения здесь

atineoSE
источник
0

В XCode версии 9.0.1 WKWebView доступен в Interface Builder.

ManuelMB
источник
0

Подключил WebKit, теперь он работает!

пример

рассвет чжоу
источник
0

Не уверен, что это поможет, но я решил проблему за себя, включив фреймворк WebKit для цели. Не вставляйте просто ссылку. Я все еще использую объект WebView в IB и перетаскиваю его на ViewController, в который я его встраиваю, и у меня никогда не было проблем ...

Я работал над 4 проектами WKWebView MacOS, и WebView работал правильно в каждом проекте.

ranTrek
источник
-14

Это сработало для меня в Xcode 7.2 ...

Сначала добавьте веб-представление в качестве выхода UIWebView в раскадровке / IB. Это даст вам такое свойство:

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

Затем просто отредактируйте свой код, чтобы изменить его на WKWebView.

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

Вы также должны изменить настраиваемый класс на WKWebView в инспекторе удостоверений.

Пэт МакГи
источник
Я пробовал это с проектом OS X - это не работает, так что это должен быть особый случай для iOS.
henrikstroem
2
То, что вы делаете, похоже на приведение типов. Он вообще НЕ может изменить тип webView.
DawnSong