Xcode 9 GM - WKWebView NSCoding support was broken in previous versions
Asked Answered
S

10

177

Does anyone know how to fix this error with Xcode 9 GM? I'm working on an app made with Xcode 8.3, the deployment target is for iOS 9.3 and I never had this problem before. I don't find any information here or on Apple forums yet :(

Edit: This error came when I put a WKWebView into interface builder, not if I use it programmatically.

See picture WKWebView Error

Edit 2: Well, it's finally not a bug, see Quinn's answer below to have more information about this behavior. Thanks to him for the explanation.

Seagraves answered 14/9, 2017 at 14:20 Comment(3)
See my answer below. This is not a bug in Xcode 9; without this build error, you would instead get a crash in -initWithCoder: at runtime prior to iOS 11.Ottillia
I just change my deployment target to 11Isolation
This should be a comment on Kampai's answer, but I don't have enough reputation points to comment. Besides explicit iOS versions the 'Builds for' dropdown in the 'File Inspector' also contains the Deployment Target (..) option. I prefer managing versions at a single place if possible and wanted to change the build target anyway. I was fully confused it still said Deployment Target (9.3) although I changed the corresponding entry in the general settings to 11.0. Restart of XCode (11.3.1) was necessary to make everything work as expected, the option 'Deployment Target (11.0)' wasJoust
O
173

The error is correct behavior, and not a bug in Xcode 9. Although WKWebView was introduced in iOS 8, there was a bug in -[WKWebView initWithCoder:] that was only fixed in iOS 11, which always crashed at runtime and thus prevented configuring one within Interface Builder.

https://bugs.webkit.org/show_bug.cgi?id=137160

Rather than allow developers to build something in IB that would be broken at runtime, it is a build error. It's an inconvenient limitation since iOS 11 was only recently released, but there's really no other good option.

The workaround for older deployment targets is to continue to add the WKWebView in code, as @fahad-ashraf already described in his answer:

https://developer.apple.com/documentation/webkit/wkwebview

Ottillia answered 9/10, 2017 at 14:57 Comment(3)
Hi Quinn, I believe the man who works at Apple :-) I also found your bug report about that : lists.webkit.org/pipermail/webkit-unassigned/2014-September/… Thank you for your answer it's really surprising for new developers like me when we encountering a behavior like that. Thanks again.Seagraves
what if we want to support in ios10 also?. in my app i need to support ios 10 also.How can we solve this issue?Jaffna
just curious why did it take Apple until iOS 11 to figure out a fix?Mommy
R
100

This seems to be a bug in Xcode 9 and was also present in the betas. You will only get the build error if you are creating a WKWebView through the storyboard. If you progmatically create the WKWebView in the corresponding ViewController class file, you should be able to build on iOS versions below iOS 11. Here is the approach given on Apple's website for how to accomplish this:

import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {

    var webView: WKWebView!

    override func loadView() {
        super.loadView()
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }
    override func viewDidLoad() {
        super.viewDidLoad()

        let myURL = URL(string: "https://www.apple.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }}

You should then be able to implement WKWebView functionality as you normally would.

Source: https://developer.apple.com/documentation/webkit/wkwebview

Romilda answered 21/9, 2017 at 14:35 Comment(5)
don't forget super.loadView()Outthink
super.loadView() has to be at the beginning. Without it, nothing shows.Hrutkay
hi :), do you know how I can set the constraints of this webview to below my NavigationBar? This solution of you works but it covers the whole screen.Chive
@AbedNaseri i think you don't need to put constraints... you can instantiate storyboard and then self.navigationController?.pushViewController(youVC, animated: true) .Adaline
programmatically set the frame / constrain is the key. ps. I didn't use super.loadView()Impound
K
64

If you want to realize a custom UIViewController with other components in addition you can make a "container" through the storyboard called for example webViewContainer:

import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
    @IBOutlet weak var webViewContainer: UIView!
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let webConfiguration = WKWebViewConfiguration()
        let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: self.webViewContainer.frame.size.width, height: self.webViewContainer.frame.size.height))
        self.webView = WKWebView (frame: customFrame , configuration: webConfiguration)
        webView.translatesAutoresizingMaskIntoConstraints = false
        self.webViewContainer.addSubview(webView)
        webView.topAnchor.constraint(equalTo: webViewContainer.topAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: webViewContainer.rightAnchor).isActive = true
        webView.leftAnchor.constraint(equalTo: webViewContainer.leftAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: webViewContainer.bottomAnchor).isActive = true
        webView.heightAnchor.constraint(equalTo: webViewContainer.heightAnchor).isActive = true
        webView.uiDelegate = self
        
        let myURL = URL(string: "https://www.apple.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
Kelpie answered 18/10, 2017 at 8:35 Comment(4)
Thank you so much, it's really help. It's a bug know by AppleLull
Worked! tested in iOS 11 and swift 4.1Jobina
If you are getting the error [LayoutConstraints] Unable to simultaneously satisfy constraints, don't forget the line webView.translatesAutoresizingMaskIntoConstraints = false. If you leave it set to true, it will create a whole set of constraints for your webView automatically which will conflict with the constraints you add programmatically. Apple Docs.Maudemaudie
Just change the following line From: let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 0.0, height: self.webViewContainer.frame.size.height)) To: let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: self.webViewContainer.frame.size.width, height: self.webViewContainer.frame.size.height))Alodie
A
62

If you are moved from older target to iOS 11.0 and still you are getting this error, then use below solution.

  1. Go to Storyboard (Main.storyboard), click on any Scene.
  2. Select 'File Inspector' which is the right side property window of Xcode
  3. Change 'Builds for' value to 'iOS 11.0 and Later'
  4. Compile and Build

enter image description here

Actinotherapy answered 24/9, 2018 at 6:33 Comment(7)
@VyachaslavGerchicov: I don't know about you, but in the industry, we do have such older projects which need to be converted to newer tech. So many facing the same problem. I already mentioned in the answer that "if you are moved from older target". Don't think of only one case.Actinotherapy
This works for me thanks for pointing this annoying IB setup. The warning is gone right away. Actually, I think this more practical and should be accepted answer. Agree with @Kampai, actually, we are forced to move to the new version of iOS, since the Apple keep changing their fundamental frameworksCarnelian
After doing it when running on simulator with iOS 10.x app crashes.Heptastich
@Ramis: I was doing it for iOS 10, I never got app crash, what was the crash log?Actinotherapy
@Kampai: Currently I can not remember exact crash log. So can not answer to your question.Heptastich
Simplest solution for fixing this issue. Thanks!Moncton
For those considering building for iOS 11 and above, as of August 6, 2019 only 3% of users are using < iOS 11.Glossographer
N
18

I have faced the same issue but it can be tackle if we add WKWebView programmatically.

  1. Do whatever design you want to make in storyboard but leave the room for WKWebView, in that area drag & drop a view and name it as webViewContainer and declare these two properties,

    @property (weak, nonatomic) IBOutlet UIView *webViewContainer;
    @property(nonatomic, strong)WKWebView *webView;
    
  2. Now create and add webView like this:

    -(instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        self.webView = [self createWebView];
        self = [super initWithCoder:aDecoder];
        return self;
    }
    

    createWebView function is declared as,

    -(WKWebView *)createWebView
    {
         WKWebViewConfiguration *configuration = 
                   [[WKWebViewConfiguration alloc] init];
         return [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
    }
    
  3. Now add this newly created webView to your containerView, like this, :

    -(void)addWebView:(UIView *)view
    {
          [view addSubview:self.webView];
          [self.webView setTranslatesAutoresizingMaskIntoConstraints:false];
          self.webView.frame = view.frame;
    }
    
  4. Finally, just load your Url like this,

    -(void)webViewLoadUrl:(NSString *)stringUrl
    {
         NSURL *url = [NSURL URLWithString:stringUrl];
         NSURLRequest *request = [NSURLRequest requestWithURL:url];
         [self.webView loadRequest:request];
    }
    

Thanks for reading this.

Nuthouse answered 2/11, 2017 at 7:34 Comment(0)
D
5

WebKit was introduced in iOS 8 but it was released with an error which caused in a runtime crash, If you are using Xcode 9/10, your project configuration support less than iOS 11 and if you are trying to add WKWebView using interface builder. Xcode immediately shows a compile-time error.

WKWebView before iOS 11.0 (NSCoding Support was broken in the previous version)

Although WKWebView was introduced in iOS 8, there was a bug in –[WKWebView initWithCoder:] that was only fixed in iOS 11.

enter image description here

Resolution is you must add WKWebView through code (Only if you are supporting below iOS 11). That actually sounds strange.

Another solution is to change the Interface Builder Document Builds for the option to iOS 11 and later (If you’re migrating from older target to iOS 11 and still getting the same error).

Dramatize answered 18/9, 2019 at 2:54 Comment(0)
D
3

//For Swift

import WebKit

class ViewController: UIViewController {
var webView: WKWebView!

// MARK:- WebView Configure
override func loadView() {
    let webConfig = WKWebViewConfiguration()
    webView = WKWebView(frame: .zero, configuration: webConfig)
    view = webView
}


override func viewDidLoad() {
    super.viewDidLoad()
    // call urlrequest fun
    loadURLRequest()
}

//MARK:- Webview URLRequest
func loadURLRequest()  {
    let urlString = "https://www.google.com"
    let url = URL(string: urlString)
    let urlRequest = URLRequest(url: url!)
    webView.load(urlRequest)
}
}

// For Objective C

#import <WebKit/WebKit.h>

@interface ViewController ()<WKNavigationDelegate,WKUIDelegate>{
WKWebView *webView;
}

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
    
NSURL *url = [[NSURL alloc] initWithString: @"https://www.google.com"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
    [webView loadRequest: request];
}


- (void)loadView {
[super loadView];

WKWebViewConfiguration *configu = [[WKWebViewConfiguration alloc] init];
webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configu];
webView.UIDelegate = self;
self.view = webView;
}

@end

enter image description here

Dioecious answered 26/6, 2020 at 9:35 Comment(0)
G
0
import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate {
    
    @IBOutlet weak var webViewContainer: UIView!
    private var webView: WKWebView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        addWebView()
        
        let myURL = URL(string: "https://www.apple.com")
        if let myURL = myURL {
            let myRequest = URLRequest(url: myURL)
            webView?.load(myRequest)
        }
    }
    
    private func addWebView() {
        let webConfiguration = WKWebViewConfiguration()
        let size = CGSize.init(width: 0.0, height: self.webViewContainer.frame.size.height)
        let customFrame = CGRect.init(origin: CGPoint.zero, size: size)
        self.webView = WKWebView (frame: customFrame, configuration: webConfiguration)
        if let webView = self.webView {
            webView.translatesAutoresizingMaskIntoConstraints = false
            self.webViewContainer.addSubview(webView)
            webView.topAnchor.constraint(equalTo: webViewContainer.topAnchor).isActive = true
            webView.rightAnchor.constraint(equalTo: webViewContainer.rightAnchor).isActive = true
            webView.leftAnchor.constraint(equalTo: webViewContainer.leftAnchor).isActive = true
            webView.bottomAnchor.constraint(equalTo: webViewContainer.bottomAnchor).isActive = true
            webView.heightAnchor.constraint(equalTo: webViewContainer.heightAnchor).isActive = true
            webView.uiDelegate = self
        }
    }
}
Gabrielson answered 6/7, 2020 at 8:59 Comment(0)
C
0

You can just set IPHONEOS_DEPLOYMENT_TARGET >= 11

[Deployment Target]

Cymry answered 28/4, 2021 at 16:35 Comment(0)
J
-5

UIWebView is deprecated in iOS11 and WKWebView works only in iOS11 - this sounds like a bug in Xcode GM.

Joanajoane answered 15/9, 2017 at 14:20 Comment(1)
Yep. The only workaround I found if you want to deploy on previous version of iOS is to add your WKWebView programmatically.Seagraves

© 2022 - 2024 — McMap. All rights reserved.