13 Replies
      Latest reply on May 1, 2019 8:42 AM by john daniel
      ethur Level 1 Level 1 (0 points)

        I've been attempting to make a simple, test macOS app using WKWebView. I've seen lots of samples and basic tutorials, and this rudimentary sample code works when tested directly in the XCode environment:

         

        import Cocoa
        import WebKit
        
        class ViewController: NSViewController {
        
            @IBOutlet weak var webView: WKWebView!
           
            override func viewDidLoad() {
                super.viewDidLoad()
               
                var myURL: URL!
                myURL = URL(string: "https://developer.apple.com/")
                let myRequest = URLRequest(url: myURL!)
                webView.load(myRequest)
        
            }
        
        }

         

        When it runs, I see an app window with an embedded WKWebView frame, and the specified URL loads within that frame as expected.

         

        However, when I attempt to run the built app file directly on my iMac, all I get is an empty window. I don't even see the frame for the WKWebView object.

         

        The WKWebView was placed in the main.storyboard and the outlet was linked through the standard ctrl-drag operation. The entitlements for App Sandboxing and Network Outgoing Connections are set (otherwise, the URL won't load in Xcode, either).

         

        So, my question is -- should this work? I've seen comments around the web that one cannot implement WKWebView via Interface Builder in older versions of Xcode/macOS, but my tests show it currently works within Xcode 10.2 on macOS 10.14.4. Why would it work in Xcode but not in the built app itself? Am I missing something?

        • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
          Claude31 Level 8 Level 8 (6,565 points)

          I've just tested and it works, both in XCode and when option-dragging the app outside.

           

          Conf: XCode 10.1ß3

          Storyboard, no sandbowing

          OSX 10.13.6

           

          But I did not use an IBOutlet for webView, which causes an error

          Swift : error: Class Unavailable: WKWebView before macOS 10.12 (NSCoding support was broken in previous versions)

          see:

              // https://stackoverflow.com/questions/46221577/xcode-9-gm-wkwebview-nscoding-support-was-broken-in-previous-versions

           

          So, that should work with 10.13, but visibly, it does not…

           

          So, my running code is:

          import Cocoa
          import WebKit
          
          class WebViewController: NSViewController, WKUIDelegate {
            
              var webView: WKWebView!
            
              override func loadView() {
                  super.loadView()
                  let webConfiguration = WKWebViewConfiguration()
                  webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 400, height: 400), configuration: webConfiguration)
                  webView.uiDelegate = self
                  view = webView
              }
            
              override func viewDidLoad() {
                  super.viewDidLoad()
                
                  var myURL: URL!
                  myURL = URL(string: "https://developer.apple.com/")
                  let myRequest = URLRequest(url: myURL!)
                  webView.load(myRequest)
                
              }
            
          }

           

           

          UPDATE

           

          Just tested (same environment) with sandbox activated. DOES work also.

           

          So, my guess:

           

          don't define webView in IB, but directly in code as shown above.

          May be there are some remains of the previous bug…

          • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
            john daniel Level 3 Level 3 (450 points)

            This appears to be a well-known problem since at least 2015: www.openradar.me/23699297

              • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
                ethur Level 1 Level 1 (0 points)

                It just seems odd that it's working within Xcode without any error messages. If it didn't work at all, then it would make more sense.

                  • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
                    john daniel Level 3 Level 3 (450 points)

                    I tried it but I was unable to get an IB WKWebView to work in any context. In my app, I can creating web views as needed and expanding them to fill their container.

                      • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
                        ethur Level 1 Level 1 (0 points)

                        Any tips on setting the sizing? So far I can only get the WKWebView to fill the entire window, no matter what CGRect values I use. I need to push the top of the view down to make room for some controls, then it should otherwise fill and resize with the rest of the window on the left, right and bottom.

                          • Re: WKWebView via Interface Builder, runs in Xcode but not in built macOS app
                            john daniel Level 3 Level 3 (450 points)

                            I put this method in an NSView cateory:

                             

                            // Expand this view to fit its superview.
                            - (void) expandToFit
                              {
                              NSLayoutConstraint * leading = 
                                [NSLayoutConstraint 
                                  constraintWithItem: self 
                                  attribute: NSLayoutAttributeLeading 
                                  relatedBy: NSLayoutRelationEqual 
                                  toItem: self.superview 
                                  attribute: NSLayoutAttributeLeading 
                                  multiplier: 1.0 
                                  constant: 0.0];
                                   
                              NSLayoutConstraint * trailing =
                                [NSLayoutConstraint 
                                  constraintWithItem: self 
                                  attribute: NSLayoutAttributeTrailing
                                  relatedBy: NSLayoutRelationEqual 
                                  toItem: self.superview 
                                  attribute: NSLayoutAttributeTrailing 
                                  multiplier: 1.0 
                                  constant: 0.0];
                                
                              NSLayoutConstraint * top = 
                                [NSLayoutConstraint 
                                  constraintWithItem: self 
                                  attribute: NSLayoutAttributeTop
                                  relatedBy: NSLayoutRelationEqual 
                                  toItem: self.superview 
                                  attribute: NSLayoutAttributeTop
                                  multiplier: 1.0 
                                  constant: 0.0];
                            
                              NSLayoutConstraint * bottom = 
                                [NSLayoutConstraint 
                                  constraintWithItem: self 
                                  attribute: NSLayoutAttributeBottom
                                  relatedBy: NSLayoutRelationEqual 
                                  toItem: self.superview 
                                  attribute: NSLayoutAttributeBottom
                                  multiplier: 1.0 
                                  constant: 0.0];
                                
                              [self.superview addConstraint: leading];
                              [self.superview addConstraint: trailing];
                              [self.superview addConstraint: top];
                              [self.superview addConstraint: bottom];
                              }
                            
                            

                             

                            It's Objective-C, but should be trivial to convert to Swift. I just add the WKWebView. I set an onLoad completion handler and then start the view loading. When the loading completes, I add the web view to a superview with animation and call expandToFit. I position the superview in IB like normal. Make sure to call setTranslatesAutoresizingMaskIntoConstraints: NO after creating the web view.