Monday, November 7, 2016

Understanding iOS WKWebview

Apple recommends to use WKWebview and not use UIWebView starting from iOS 8 as mentioned in https://developer.apple.com/reference/webkit/wkwebview. Developers need to better understand the functions provided by WKWebview.

1. WKWebView

The core object is WKWebView class, the WKWebView has to be created programmatically and can not be added by xcode interface builder. The WKWebView class provider the basic function of loading a url, and go back/forward.

The loadRequest and loadFileURL are two key methods to load the content to the webview.

It also has an important function:
evaluateJavaScript(_:completionHandler:)
for calling an javascript code from native swift/objective-c code.

In addition, wkWebView has a customUserAgent property to easily set the user agent value.

1.1 WKBackForwardList

A list of visited pages.

1.2 WKBackForwardListItem
The url information of the back-forward navigation item

2. WKWebViewConfiguration

When initializing WKWebView instance, one parameter takes a WKWebViewConfiguration object, WKWebViewConfiguration contains a set of properties to config the wkwebview.
WKWebViewConfiguration has few importance members of sub configuration class

2.1 WKPreferences 
minimumFontSize: control miminal font in the browser

javaScriptCanOpenWindowsAutomatically: allow open window without user interaction
javascriptEnabled: whether javascript is enabled. If this property is false, then js script element defined in html file will not be loaded. However WKUserScript will still work. 

Besides the above instance properties, there are few settings can be set to wkwebview's wkpreference by using the setValue method
- (void)setValue:(id)value forKey:(NSString *)key;

For example, call the below method to allow JavaScript running in the context of a file scheme to access content in other file scheme URLs. 
[theConfiguration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];

The full list of properties are listed at the end of this blog.

2.2 WKProcessPool
The wkwebviewConfiguration can specify a process pool for the webview instance, if multi wkwebview instances share the same wkprocesspool object, then they can share the cookie and cache.

2.3 WKUserContentController
WKUserContentController has two main functions: (1) let native code handle javascript side posted event and (2) inject javascript code from native code when DOM loading starts or ends

2.3.1 Handle js post event from native code
WKUserContentController provides a way for javascript to post js message, and let native code to handle it by the below method:
- (void)addScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

The native handler needs to implement WKScriptMessageHandler to handle the js event. Note, the method does not provide a way to send the result back to webview, although the handler can call evaluateJavaScript method to report the result to js code. 

2.3.1.1  WKScriptMessageHandler protocol
protocol to receive js message post request with the below method
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

2.3.1.2 WKScriptMessage
WKReceiveScriptMessage object represents the message object posted by javascript side sender

2.3.2 Inject javascript from native code to js DOM
WKUserContentController allows add (and remove) a WKUserScript to be injected either when the DOM tree starts to load or finishes to load. On the contrary, evaluateJavaScript allows application to execute a javascript snippet on demand at any time.

2.3.2.1 WKUserScript
WKUserScript represents a js script code block that can be injected into the web page. It includes javascript source code, time to inject the script (DOM start or end), and whether to inject the script only to main frame or all frames


2.4 WKWebSiteDataStore
WKWebSiteDataStore specifies the data store used by a webview, including cookie, caches, and local storage.
The WKWebSiteDataStore class has static method to return the default data store, which is a singleton static instance. WKWebSiteDataStore also has another static method to always return a new nonpersitent data store.

WKWebSiteDataStore provides method (fetchDataRecordsOfTypes and removeDataOfTypes) to enumerate and delete the saved data types (cached, cookie, localstorage, etc) from the website data store.

2.4.1 WKHTTPCookieStore httpCookieStore
A cookie store manages http cookie in the website data store. This object is readonly.
Note when adding cookie change observer, WKWebView configuration will not retain the observer, it must be retained by someone else. In addition, the observer must be added to the WKWebView configuration before setting the configuration's processPool to other value, otherwise the observer will not be called when cookie change happens.

2.4.2 WKWebsiteDataRecord
WKWebsiteDataRecord represents website data grouped by url's domain and suffix

2.5 WKURLSchemeHandler (iOS 11+)
WKWebViewConfiguration can set custom url handler to customize request handling by calling the below method, similar to NSURLProtocol. 
However this only works if the root html file is also loaded using the same custom scheme. If the root html file is loaded by file:// or http:// (or https://), then setting the registered custom scheme handler will not work.
- (void)setURLSchemeHandler:(id<WKURLSchemeHandler>)urlSchemeHandler forURLScheme:(NSString *)urlScheme; 

3 WKNavigationDelegate

WKNavigationDelegate methods are called when loading a navigation request, for example, event to begin the load and finish the load. It also has a method to handle server side credential challenge. It uses WKNavigation object to indicate the navigation information. The delegate can decide to allow or forbid a pending navigation

3.1 WKNavigation
WKNavigation is a unique object to identify the loading progress of a page, it does not have any property or method.

3.2 WKNavigationAction
WKNavigationAction class is used by method decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction as a parameter to indicate the navigation information, so caller can decide whether allow the navigation or not  based on its information. It includes (NSURLRequest*) request, navigationType, etc.

Note if the decidePolicyForNavigationAction  method returns cancel, then the navigation error callback method will not be called. Those navigation error callback methods are only called when the page cannot be loaded for other reasons.

3.2.1 WKNavigationType
Used by WKNavigationAction to indicate the navigation type, like a link, or form submit, or back-forward request.

4 WKUIDelegate

Unlike mobile safari, WKWebView does not  handle javascript alert, confirm and prompt method by default, you need to implement WKUIDelegate to support them. 
When javascript calls the alert, confirm or prompt method, the native method in WKUIDelegate will be called, you need to show a native UIAlert dialog UI to user, once user dismiss the dialog, then calling the completion block to tell the javascript code to continue.
When the below methods are invoked from js side, the js flow is blocked, so they are synchronous methods. A particular usage for confirm and prompt method is to call the confirm or prompt method from js code and then pass some data from native code to javascript with or without UI interaction.


- (void)webView:(WKWebView *)webView 
runJavaScriptAlertPanelWithMessage:(NSString *)message 
initiatedByFrame:(WKFrameInfo *)frame 
completionHandler:(void (^)(void))completionHandler;
- (void)webView:(WKWebView *)webView 
runJavaScriptConfirmPanelWithMessage:(NSString *)message 
initiatedByFrame:(WKFrameInfo *)frame  
- (void)webView:(WKWebView *)webView 
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt 
    defaultText:(NSString *)defaultText 
initiatedByFrame:(WKFrameInfo *)frame  


Appendix: List of properties in WKPreference


telephoneNumberDetectionIsEnabled
storageBlockingPolicy
compositingBordersVisible
compositingRepaintCountersVisible
tiledScrollingIndicatorVisible
resourceUsageOverlayVisible
visibleDebugOverlayRegions
simpleLineLayoutEnabled
simpleLineLayoutDebugBordersEnabled
acceleratedDrawingEnabled
displayListDrawingEnabled
visualViewportEnabled
largeImageAsyncDecodingEnabled
animatedImageAsyncDecodingEnabled
textAutosizingEnabled
subpixelAntialiasedLayerTextEnabled
developerExtrasEnabled
logsPageMessagesToSystemConsoleEnabled
hiddenPageDOMTimerThrottlingEnabled
hiddenPageDOMTimerThrottlingAutoIncreases
pageVisibilityBasedProcessSuppressionEnabled
allowFileAccessFromFileURLs
javaScriptRuntimeFlags
standalone
diagnosticLoggingEnabled
defaultFontSize
defaultFixedPitchFontSize
fixedPitchFontFamily
offlineApplicationCacheIsEnabled
fullScreenEnabled
shouldSuppressKeyboardInputDuringProvisionalNavigation
allowsPictureInPictureMediaPlayback
applePayCapabilityDisclosureAllowed
loadsImagesAutomatically
peerConnectionEnabled
mediaDevicesEnabled
screenCaptureEnabled
mockCaptureDevicesEnabled
mockCaptureDevicesPromptEnabled
mediaCaptureRequiresSecureConnection
enumeratingAllNetworkInterfacesEnabled
iceCandidateFilteringEnabled
webRTCLegacyAPIEnabled
inactiveMediaCaptureSteamRepromptIntervalInMinutes
javaScriptCanAccessClipboard
domPasteAllowed
shouldAllowUserInstalledFonts
editableLinkBehavior

Note, an important property AllowFileAccessFromFileURLs is not supported by ios, although it is supported by Android client.

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. MahmoodApril 27, 2018 at 4:07 AM
    "4 WKUIDelegate
    Unlike mobile safari, WKWebView does not handle javascript alert, confirm and prompt method by default, you need to implement WKUIDelegate to support them.
    When javascript calls the alert, confirm or prompt method, the native method in WKUIDelegate will be called, you need to show a native UIAlert dialog UI to user, once user dismiss the dialog, then calling the completion block to tell the javascript code to continue."

    Can you please teach this? I've been trying this past 2 days but it doesn't work

    ReplyDelete