网上浏览 Interface Builder

XCode6beta 中的 IB 对象模板似乎仍在创建旧式对象(iOS 的 UIWebView 和 OSX 的 WebView)。希望苹果能够为了现代的 WebKit 更新它们,但是在那之前,什么才是在 Interface Builder 中创建 WKWebViews 的最佳方式呢?我是否应该创建一个基本视图(UIView 或 NSView)并将其类型分配给 WKWebView?我在网上找到的大多数示例都是通过编程方式将它添加到容器视图中; 出于某种原因,这样做是否更好?

68506 次浏览

As pointed out by some, as of Xcode 6.4, WKWebView is still not available on Interface Builder. However, it is very easy to add them via code.

I'm just using this in my 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)
}
}
}

You are correct - it doesn't seem to work. If you look in the headers, you'll see:

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

which implies that you can't instantiate one from a nib.

You'll have to do it by hand in viewDidLoad or loadView.

This worked for me in Xcode 7.2...

First add the web view as a UIWebView outlet in the storyboard / IB. This will give you a property like this:

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

Then just edit your code to change it to a WKWebView.

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

You should also change the custom class to WKWebView in the Identity inspector.

With Xcode 8 this is now possible, but the means of achieving it is a little hacky to say the least. But hey, a working solution is a working solution, right? Let me explain.

WKWebView's initWithCoder: is no longer annotated as "NS_UNAVAILABLE". It now looks as shown below.

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

Start by subclassing WKWebView and override initWithCoder. Instead of calling super initWithCoder, you'll need to use a different init method, such as initWithFrame:configuration:. Quick example below.

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

Over in your Storyboard, use a UIView and give it a custom class of your new subclass. The rest is business as usual (setting auto-layout constraints, linking the view to an outlet in a controller, etc).

Finally, WKWebView scales content differently to UIWebView. Many people are likely going to want to follow the simple advice in Suppress WKWebView from scaling content to render at same magnification as UIWebView does to make WKWebView more closely follow the UIWebView behaviour in this regard.

Info.plist

add in your Info.plist transport security setting

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

Xcode 9.1+

Using interface builder

You can find WKWebView element in the Object library.

enter image description here

Add view programmatically with 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

Add view programmatically with Swift 5 (full sample)

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

Here's a simple Swift 3 version based on crx_au's excellent answer.

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

Create a UIView in Interface Builder, assign your constraints, and assign it WKWebView_IBWrapper as a custom class, like so:

Utilities -> Identity Inspector Tab[1]

This is now apparently fixed in Xcode 9b4. The release notes say "WKWebView is available in the iOS object library."

I haven't looked deeper to see if it requires iOS 11 or is backward compatible yet.

In XCode Version 9.0.1 WKWebView is available on Interface Builder.

If you still face this issue in recent versions of Xcode, i.e. v9.2+, simply import Webkit to your ViewController:

#import <WebKit/WebKit.h>
  1. Before the fix: enter image description here

  2. After the fix:

enter image description here

You can instantiate and configure a WKWebView in IB since Xcode 9, no need to do it in code. enter image description here

Note that your deployment target has to be higher than iOS 10 though or you will get a compile-time error.

enter image description here

I've linked WebKit, now it's working!

example

Not sure if this helps but I solved the problem for me by including the WebKit framework for the target. Don't embed it just link the reference. I still use the WebView object in IB and drop it on the ViewController I'm embedding it in and I've never had a problem...

I've worked on 4 WKWebView MacOS projects now and the WebView has worked properly in each project.