15

I am updating my project from UIWebView to WKWebView. In existing UIWebView approach where UIWebView does't have any parent until it runs javascript and once it has content, it adds a parent to the webview. Content renders fine using UIWebView. I am using the same approach for WKWebView, however WKWebview stuck at loading. Is there any way we can execute javascript on wkwebview without adding parent to the webview. Another interesting thing is it works on simulator not on device. Using localHTTPServer to serve the html, css and images.

Any Suggestions or Tips to solve the above issue.

Subba
  • 637
  • 1
  • 7
  • 13

2 Answers2

17

I have observed similar behavior in my app running socket.io in a headless WKWebView. In my case, the web socket would disconnect all the time and not reconnect.

It seems that since WKWebView runs javascript off-process that it will pause any javascript that is considered idle to save resources (<-IMO). Idle includes not having a parent or the app/device is inactive. So, yes, it seems like you are correct in that it needs a parent view in most cases. I was able to work around this using the following code:

WKWebViewConfiguration* webViewConfig = // set up config

// provide empty frame rect
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webViewConfig];

// add to keyWindow to ensure it is 'active'
[UIApplication.sharedApplication.keyWindow addSubview:webView];

This approach at least ensures the javascript runs while the app is active and doesn't effect the UI. If you need to display it later you can remove the webView from the keyWindow after render and reset the frame. And, yes, I also observed that in the simulator this is not an issue (javascript ALWAYS runs, regardless of parent or app state)

Hope this helps!

mattr
  • 5,458
  • 2
  • 27
  • 22
  • 2
    Wow. Amazing,the way you got the workaround. It works. However at some point we should remove webview from keywindow right? Otherwise performance or memory constraints might show up. – Subba Oct 28 '14 at 07:06
  • 1
    it depends. for me i need it running all the time to keep the socket connection going. but sure, if you don't need it running, why not remove it :). – mattr Oct 28 '14 at 13:32
  • Is this raised with Apple as a bug, any open radar exists. – Sachin Vas Feb 28 '17 at 06:49
  • another interesting thing, in iOS 10-11 I've found that you can, actually, run JavaScript on WKWebView without adding it to the tree of views. But, if it is not in the tree, the performance of exection the JavaScript slows down (timers on the page slows down up to 5 times). And, also, in Safari browser on macOS the execution slows down if the tab of your page is hidden: our timers, when page dissappeared (like we opened another tab), got slow down about 3-5 times. – Eugene Biryukov Aug 04 '18 at 09:55
  • This is pure gold! Especially when working with cordova-plugins this extremely useful, thank you! – David Oct 11 '18 at 13:54
8

The accepted solution worked for me some of the time. I tried something else which appears to work for me consistently:

self.keepWebViewActiveTimer = [NSTimer scheduledTimerWithTimeInterval:0.2
                                 target:self 
                                 selector:@selector(_keepWKWebViewActive:)
                                 userInfo:nil
                                 repeats:YES];

Where _keepWKWebViewActive is:

-(void) _keepWKWebViewActive:(NSTimer*) timer{
    if(self.webView) {
        [self.webView evaluateJavaScript:@"1+1" completionHandler:nil];
    }
}
nabriski
  • 81
  • 1
  • 2