Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WKWebView does not re-render content while loading another URL

I'm currently developing an application that uses a UIWebView to display some content. It used to work fine with UIWebView, but we decided to switch to WKWebView when we raised the OS requirement to 8.1. We noticed a huge improvement in performance, but some simple think that used to work fine, started failing now. After some research, I managed to see what's going on - but I don't see how to fix it. I was wondering if someone could lend me a hand on this...

The URL our webview loads takes quite a lot of time to finish the job, so before starting the request we load a static spinner so the user doesn't feel like the app has gone nuts. The load cycle for that static content is already tuned up, so we don't start the URL request until the static content has been correcty loaded. This works fine, as long as the user doesn't rotate the device. This is what can be seen:

(I had to change the view for privacy purposes. I'm not the owner of this code, after all :-))

enter image description here

I'm using this html code to test the size. The body's background color is dark gray, and the ugly light gray box expands to the 100% of the width, substracting the margins. So far so good. But if the user rotates the device, this is what happens:

enter image description here

This is creepy, since apparently the body's stetching to match the maximum width, but the inner div is handling a wrong relative size. This goes on as long as the request is being processed. When I force a timeout to make the request fail, the WKWebView re-renders and shows its correct appearance:

enter image description here

Once I discovered this I tried, without success, to subscribe to the rotation observer and force re-renders on the webview by:

  • Calling viewNeedsDisplay for both the UIWebView and the UIScrollView inside
  • Re-sizing the UIWebView
  • Re-positioning the UIScrollView content

So, my conclusions so far:

  • This didn't happen on an UIWebView, just on the new WKWebView (I tested this again, confirmed)
  • Looks like WKWebView doesn't render views correctly while it's on loading status

Does somebody know if there's a way to fix this? Something like one magical property I'm missing that comes disabled by default? I don't want to think they broke this part when they remade the webview... Thanks in advance :)

Edit: Stuff I tried since the creation of the post, without success:

  • Changing the DOM asyncronally, through the use of javascript/native rotation callbacks doesn't work. The changes don't get rendered until the http request ends.
  • Calling the http request in a different thread using the dispatch_async method doesn't work. Under the hood, the WKWebview probably ends up using the same thread as if you call it from the main thread.
like image 513
Bartserk Avatar asked May 04 '15 16:05

Bartserk


1 Answers

If you don't mind getting a bit hacky, there are ways to do it with Javascript:

  1. You could add Javascript that detects changes such as window.orientation and window.onresize. See if any frame-related event gets called. If they are called, simply resize the div yourself with Javascript.

  2. If the events never get fired, you can fake them yourself using evaluateJavaScript:completionHandler:

  3. You could also make your own events that way. Simply send a resize div script whenever you detect a change in the device's orientation within your app.

  4. If you are loading Javascript, you could look at the async and defer of the <script> tag. This means you will have to change the code in the webview.

It's not the best way of approaching this, but it will require the least amount of change.

I also suggest you fill a bug report at https://bugreport.apple.com/, so that you can know if it is an expected behavior or not.

like image 144
Moustach Avatar answered Oct 01 '22 16:10

Moustach