iOS in-app browser choices
In iOS we have mainly two ways: SFSafariViewController and WKWebView.
SFSafariViewController
If we don’t need deep customization,
SFSafariViewControlleris the best choiceBuilt on top of
WKWebViewIt handles everything for you
Provides many Safari features such as:
reader
content blockers
autofill
and more
WKWebView
More customizable
Protects your application’s code and data from the complexities of the web platform
The web content runs in a separate process
What’s new in WKWebView
Isolating your app from web content
To disable javascript, use the new
WKWebPagePreferences.allowsContentJavaScriptinstead of the deprecatedWKPreferences.javaScriptEnabledWKContentWorldmakes sure that your javascript doesn’t interfere with the website’s javascript (e.g. by declaring the same function) and vice versa:use
evaluateJavaScript(_:in:in:completionHandler:)and pass either.defaultClient(your own default world),.page(the webpage’s), or.world(name:)(for a custom world)You can also inject
WKScriptMessageHandlerin different words in order to isolate those as well
Communicating with JavaScript
callAsyncJavaScriptmakes reusing the same script with different values much more like native functions:
let styleJavaScript = """
var element = document.getElementById(elementIDToStylize);
if (!element)
return false;
for (const theStyle in stylesToApply)
element.style.theStyle = stylesToApply[theStyle];
return true;
"""
webView.callAsyncJavaScript(
styleJavaScript,
arguments: [
"elementIDToStylize)": "postContainer",
"stylesToApply": [
"margin": 0,
"padding-left": "5px"
]
],
in: .defaultClient,
completion: { _ in
// check the return value if desired
}
)With
callAsyncJavaScriptserialization and de-serialization of argument types happens automaticallyThe
callAsyncJavaScriptcompletion block is called only after the script code says so: it the script returns a promise, it will call the completion block only after the promise has been fulfilled.
More flexible rendering
Use
WKWebView.pageZoominstead of changing the CSS zoom with JavaScript. This will make sure that the zoom is set before the page is rendered.Use
WKWebView.mediaTypeto set a custom media type (used in css queries)
Working with web content
Use
find(_:configuration:completionHandler:)to offer a native way to find a string in the content similarly to how Safari doesUse
createPDF(configuration:completionHandler:)to share the whole web view similar to how sharing in Safari worksWKWebView has learned to create Web Archives with createWebArchiveData(completionHandler:)
Respecting privacy
Intelligent Tracking Prevention (ITP) is enabled by default on all
WKWebViews on iOS 14 and macOS 11
App-bound domains
you specify which domains are the core part of the implementation of your app
deep interaction with the web content not core to your app is disabled, making it impossible for user data to be accidentally compromised by other domains
Define your domains in the app info.plist:
<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
<string>webkittens.internal.apple.com</string>
<string>pupsonsafari.internal.apple.com</string>
</array>
</dict>
</plist> 