What is UIWebView?• Original web rendering component
introduced in iOS 2.0 • This is what was historically used to build out
hybrid apps or load any web content inside an iOS app
UIWebView !== Safari• Mobile Safari tends to load pages 2-3x faster
than a UIWebView • Changes and fixes applied to Safari often not
ported into UIWebView • UIWebview is clunky, crashy, leaks memory • Scrolling blocks images loading and animation • Different JavaScript engine than Safari (not Nitro)
Why does UIWebView not have Nitro?
Nitro is excluded because Apple wanted to make hybrid apps less performant and force everybody to use their native platform
Excluded due to security reasons. Running a Just-In-Time compiler requires marking pages in RAM as executable - iOS does not allow this out of security concerns (except in Safari)
Cynical Answer Real Answer
WKWebView
Introduced in iOS 8 to give developers a performant webview (“same” performance as Safari)
WKWebView's rendering is all done in a separate process owned by the WKWebView
WKWebView also gives us…• Significant performance gains in WebGL
applications (though supported in UIWebview) • Less "crashy" behaviour when rendering bugs
are triggered from HTML/CSS/JavaScript
More benefits!• Faster JavaScript and page rendering (thanks Nitro!) • 60fps interactive scrolling • Better communication between Swift and JS
(we haven’t experimented with this yet) • Since we are sharing the JS engine with
Safari, WKWebView should be better maintained and more reliable
How do I implement WKWebView?
• Don’t worry, there’s a ton of great documentation!
• What was formerly a single class (UIWebView) and protocol (UIWebViewDelegate) is now 14 classes and 3 protocols (WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate)
• Other than class docs (and StackOverflow), no official “How-To WKWebView” from Apple
WKWebView Related ClassesWKBackForwardList WKBackForwardListItem WKFrameInfo WKNavigation WKNavigationAction WKNavigationResponse WKPreferences WKProcessPool WKScriptMessage
WKSecurityOrigin WKUserContentController WKUserScript WKWebViewConfiguration WKWebsiteDataRecord WKWebsiteDataStore WKWindowFeatures WKWebView
More code required• Automatically handled by UIWebView
• App store links
• JS alerts, confirms, inputs
• Sharing cookies between web views
How do I implement WKWebView?
• High-level: copy the files we need to load into a /tmp directory that we can load files from
• Alternative: serve files we need from a web server in the app
• Solution: Fixed in iOS 9
Cannot intercept POST requests• POST bodies are missing in NSURLRequest
sent to delegate methods • Solution: for now leave it -- in line with
Android behaviour • Good news: WebKit forums indicate this is a
bug and there seems to be a bit of traction
No state preservation participation
• WKWebView doesn’t conform to the state preservation API (no restorationIdentifier)
• In Astro its used to reduce memory footprint and prevent crashes
• Solution: build our own by saving the last known URL
• Seeing some webviews display about:blank for no reason upon navigating back
• Appears to be a memory issue
WSOD: White Screen of Death
WSOD - Our Solution
We poll each webview that we manage and not currently visible (in the view hierarchy)
• Happens when the frame is not set before load completes http://www.openradar.me/22855188
• Had to get creative on this one. • Turns out, duplicate <head> tags are ignored… • … so we create a <head> tag at the beginning JUST
to scroll back up
Views Appear Halfway Down
View Doesn’t Render Until Visible
• Big problem for preloading tabs in a tab bar layout
• Bigger problem if you rely on Javascript to run in those webviews
• Solution is an off-screen “holding pen” for web views not currently visible
WKWebView and Certs• Bug in WKWebView where the documented
way of doing custom analysis of SSL certificates is broken
• webView(_:didReceiveAuthenticationChallenge:completionHandler:) is never called
• Important for internal use • No workaround
Need to know about these:• When app is sent to background, JS stops executing in ~10sec
while native code (and JS in UIWebView) keeps running for ~3 min until completely suspended by OS.
• Unlike UIWebView, the webView.URL property is updated to the navigation target the first delegate method is called by WKWebView.
• App store links don’t work by default -- have to intercept requests (http://atmarkplant.com/ios-wkwebview-tips/#applink)