iOS WKWebView JS doesn't update attribute modification when app in background

0 votes
asked Sep 11, 2017 by user2875404

Hey I have an iOS app with Watch Extension. When launching the Apple Watch app it launches the iPhone app and keeps it alive by sending sendMessage calls every couple of seconds. The iPhone app then navigates to a website in a WKWebView, checks its content every couple of seconds and then sends some of the data to the Apple Watch in order to be displayed there.

Displaying the constantly-updating content on the Apple Watch works perfectly fine, I am getting the data on the iPhone like that:

self.webView.evaluateJavaScript("document.documentElement.outerHTML.toString()",
                                   completionHandler: { (html: Any?, error: Error?) 

. . . //splitting html content into TFHppleElements

self.contentArray.add((element.search(withXPathQuery: "//div[contains(@class, 'article-title')]")[0] as AnyObject).content)

which I run every 5 seconds. As soon as the text in the article-title changes, the changes are visible on my Watch. Works.

The elements all contain something like style="z-index: 206; height: ... and I successfully parse it by grabbing the attributes and then sub-stringing it down.

let styleContainer = element.attributes["style"] as! String
var firstHalf = styleContainer.components(separatedBy: "; height:")
...

I used the z-index value to sort the table rows on my Apple Watch but after 1-3 updates, the z-index of all the elements stopped updating. The contents (like the article-title) were still being updated so the data-flow was definitely working but I was wondering why the z-index' stayed the same. At first I thought that it's an issue with my sorting or during transfer to the Apple Watch but I wasn't able to pin down this issue - when I ran the app on the iPhone, it always got the right index, but when I ran the app by launching it on the watch, the problem as described above appeared.

After days of messing with data structures (still thinking the error was on my side) it finally hit me: when the app is launched in the background, the z-index on the page itself doesn't get update. I checked this by launching the app on my Watch and getting the wrong z-index' as usual but then I kept the Watch app open and launched the app on the iPhone - I saw the WKWebView updating the order of the elements according to their z-index and suddenly I got the right z-index for every element, even after pressing the home button. This explains a lot but still doesn't really help me at solving the issue.

How can I trick the WKWebView into letting the JS update all the elements z-index when it's running in the background? What I find weird is that this problem doesn't occur after opening the iPhone app for a short period of time but I can't ask my users to open and "minimize" the app every time when wanting to access the Watch app as the purpose of a Watch app is to keep the phone in your pocket.

Activating the iPhone app by sendMessage also calls viewDidLoad so there is no real difference that I can point out between launching the app on the phone manually and doing so by Watch. Javascript itself also works in the background so why would everything update except for the z-index attributes? Preventing "graphical" updates running background would be understandable in regard to preserving battery life but isn't text "graphical", too? And why would it be different for a home-buttoned app if it's been launched manually?

Removed because below only happened once, weird.

EDIT: Ok so actually the index values change, but whenever one article gets pushed to the top, it goes to the same value as the highest value any article has without updating the value of the other ones. Example:

Before:
A1: 26
A2: 27
A3: 28
A4: 29
After pushing A1 to the top in the background:
A2: 27
A3: 28
A4: 29
A1: 29
After manually opening the app on the phone:
A2: 26
A3: 27
A4: 28
A1: 29

It seems that WebKit has issues with the z-index so let's see where the journey leads me

1 Answer

0 votes
answered Sep 13, 2017 by asleepace

Hi there I am not sure I have a definite answer for this question, but I do have a few things that you can try to help you out.

First things first you are going to want visibility on the HTML / CSS in the WKWebView, to do this you can open Safari and on the top bar click "Develop" and the third item down should be the name of your computer which will open a list of visible WebView instances. You can click on the one currently running (you should see the screen get highlighted when you hover over the option). Open this and then you can view the source, styling and use the console.

From here try to determine if the Z-Indexs are actually being updated in the WebView or not. If they are not such as I suspect, this would leave me to believe this is a caching issue. From my experience one thing that makes the WKWebView more performant than the traditional UIWebView is the caching mechanisms it has in place. It will try and cache all the CSS it can, so you might want to try to clear the cache in between loads.

let dataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache, WKWebsiteDataTypeLocalStorage])
let epoch = NSDate(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes:dataTypes as! Set<String>, modifiedSince:epoch as Date, completionHandler:{})

Notice that all instances of WKWebViews share the same data store, so you don't actually clear the data on your WebView instance but rather on the WKWebSiteDataStore.

Also I would use javascript to reload the page as well:

webView.evaluateJavaScript("location.reload();", completionHandler: nil)

If these solutions don't help I would try to reorganize the list instead of using the ZIndex using the name or id tag, these might not have the same caching issues as CSS. Hope this helps, but it would be hard to know for sure what the problem is without taking a deeper look.

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...