I. Introduction
UIWebView is a web container that came out in iOS 2, and UIWebView is the most memory-consuming control; Until iOS 8, Apple launched the WebKit framework, in which WKWebView was officially launched to replace UIWebView; In iOS 12, Apple officially abandoned UIWebView, requiring developers to completely replace UIWebView with WKWebView
Second, the comparison of characteristics
UIWebView features:
- 1. Slow loading speed
- 2. With a large memory footprint, the App can be easily killed by the system if it stays in the background
- 3. The native container does not have a progress bar and needs to be customized
WKWebView features:
- 1. There is a great improvement in performance, stability and function (the most intuitive improvement is that loading web pages occupies little memory, and the memory performance of loading different web pages is improved by 3 to 4 times, and there is no cache)
- 2, allow JavaScript Nitro library to load and use (UIWebView restrictions)
- 3. Support more HTML5 features
- 4. Same JavaScript engine as Safari
Iii. Capability provision
A. Loading capability
- UIWebView can not only load HTML pages, but also support PDF, Word, TXT and all kinds of pictures display;
- Compared to UIWebView, WKWebView also supports various file formats and has added a LoadFileURL function to load local files.
1.1 UIWebView loads web page requests
- (void)loadRequest:(NSURLRequest *)request;
Copy the code
1.2 WKWebView loads the web page request
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
Copy the code
2.1 UIWebView loads HTML
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
Copy the code
2.2 WKWebView loads HTML
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
Copy the code
3.1 UIWebView loads the file and specifies the MIME type and encoding type
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;
Copy the code
3.2 WKWebView loads the file and specifies the MIME type and encoding type
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;
Copy the code
4 WKWebView loads local files, UIWebView cannot
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL
Copy the code
B. Related to navigation refresh
Navigation related | | UIWebView WKWebView | page navigation related to explain | | – | – | – | | canGoBack | canGoBack can | back | | canGoForward | canGoForward | If you can forward | | isLoading | isLoading | is loading |
1.1 Methods related to UIWebView
// reload - (void)reload; // stopLoading - (void)stopLoading; // back - (void)goBack; // forward - (void)goForward;Copy the code
1.2 WKWebView related methods
Reload - (nullable WKNavigation *)reload; // stopLoading - (void)stopLoading; // Back - (nullable WKNavigation *)goBack; // Forward - (nullable WKNavigation *)goForward;Copy the code
Note: Different from UIWebVie, WKWebView’s methods return values (except stopLoading). The return value is WKNavigation, which is mainly used to track page loading progress.
1.3 WKWebView unique methods
Network data changes are compared, and if there is no change, a cache is used, otherwise a new request is made
- (nullable WKNavigation *)reloadFromOrigin;
Copy the code
Jumps to a specified history page
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
Copy the code
C. Agency agreement
- UIWebView’s proxy protocol is basically UIWebView del – first line
- WKWebView has three agent protocols, namely WKNavigationDelegate, WKUIDelegate and WKScriptMessageHandler.
UIWebViewDelegate & WKNavigationDelegate
The UIWebViewDelegate and WKNavigationDelegate equivalents are shown below
UIWebViewDelegate
// start loading web page - (void)webViewDidStartLoad:(UIWebView *)webView; - (void)webViewDidFinishLoad:(UIWebView *)webView; - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error; // Whether to allow loading of web pages, or get the URL that JS is about to open, By intercepting the URL can interact with JS - (BOOL) webView: (UIWebView *) webView shouldStartLoadWithRequest (NSURLRequest *) request navigationType:(UIWebViewNavigationType)navigationType;Copy the code
WKNavigationDelegate
/ / start page loading - (void) webView: (WKWebView *) webView didStartProvisionalNavigation: (null_unspecified WKNavigation *) navigation; // webView (WKWebView *)webView didFinishNavigation (Null_Unspecified WKNavigation *) Navigation; // web page loading error - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; // Whether to allow loading of web pages, or get the URL that JS is about to open, By intercepting the URL can interact with JS - (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler; - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;Copy the code
The WKNavigationDelegate intercepts the loaded proxy method, not like the UIWebViewDelegate equivalent function that returns a BOOL, but rather the decisionHandler in the block that decides whether or not to jump, Return allow or Cancel.
WKWebView’s unique agent WKScriptMessageHandler is used for interaction between App and JS and provides callback methods for receiving messages from web pages
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
Copy the code
WKScriptMessageHandler is a mandatory function for App and JS interaction, providing callback methods to receive messages from the web page, and responding to messages sent from the JavaScript code of the web page. Use the Message parameter to get the message content and determine the original Web view.
WKUIDelegate is a UI-related proxy protocol that handles three prompt boxes: enter, confirm, and warn. In UIWebView, Alert, Confirm, Prompt and other views can be executed directly, but in WKWebView, notifications need to be received through this protocol, and then executed through iOS native, that is, Web Prompt boxes need to be intercepted and processed through native.
// create a new WebView - (WKWebView *) WebView :(WKWebView *) WebView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;Copy the code
// This is often used in projects where the H5 interface has a target = __blank tag (indicating a new page to open a web page) or no response from a click on a web page.
/ JS/call alert method - (void) webView: (WKWebView *) webView runJavaScriptAlertPanelWithMessage message: (nsstrings *) initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler; / / call the JS confirm method - (void) webView: (WKWebView *) webView runJavaScriptConfirmPanelWithMessage message: (nsstrings *) initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler; / JS/call prompt method - (void) webView: (WKWebView *) webView runJavaScriptTextInputPanelWithPrompt prompt: (nsstrings *) defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler; - (void)webViewDidClose:(WKWebView *)webView;Copy the code
WKWebView history stack cache strategy
A. Basic concepts of WebKit
The WKWebView runtime has three kinds of processes working together: UIProcess, WebContent, and Networking.
1. WebContent process The process in which the WEB DOM and JS are located. The number of processes can be multiple, depending on some detailed policies. A unique WebProcess instance is created when the process is initialized and acts as a client of IPC::Connection, a proxy for communication with other processes.
UIProcess Specifies the process corresponding to the application. After initialization, WebPageProxy acts as a client of IPC::Connection and a proxy to communicate with other processes. WebPageProxy and WebProcessProxy correspond to WebContent process WebPage and WebProcess, respectively. WebProcessPool (the WKProcessPool object associated with WKWebViewConfiguration) abstracts the WebContent process pool, meaning that one WKWebView can correspond to multiple WebContent processes.
3. The Networking process is responsible for network related processing, and there is only one process to create multiple WKWebViews.
B. History stack cache strategy
Brief description: WKWebView can switch the history stack through goBack/goForward interface. There is a cache policy when switching, which can save the time of requesting network when hitting. The BackForwardCache of the WebContent process is a singleton that manages the history stack cache. UIProcess’s WebProcessPool abstracts the WebContent process pool. Each WebProcessPool has a unique WebBackForwardCache representing the history stack cache. Corresponds to each BackForwardCache singleton in the WebContent process pool. BackForwardCache uses an ordered hash table to store cached elements and sets the maximum number of cached elements:
ListHashSet<RefPtr<HistoryItem>> m_items;
unsigned m_maxSize {0};
Copy the code
1. Cache elimination strategy
The policies of BackForwardCache and WebBackForwardCache are basically the same. The following uses BackForwardCache as an example. When the WebContent process switches pages, it passes the current page through:
BackForwardCache::singleton().addIfCacheable(...) ;Copy the code
Add cache:
bool BackForwardCache::addIfCacheable(HistoryItem& item, Page* page) { ... item.setCachedPage(makeUnique<CachedPage>(*page)); item.m_pruningReason = PruningReason::None; m_items.add(&item); . }Copy the code
Maximum cache number
namespace WebKit { voidcalculateMemoryCacheSizes(...) { uint64_t memorySize = ramSize() / MB; . // back/forward cache capacity (in pages) if (memorySize >= 512) backForwardCacheCapacity = 2; elseif (memorySize >= 256) backForwardCacheCapacity = 1; else backForwardCacheCapacity = 0; . }...Copy the code
It can be seen that a simple LRU elimination strategy is implemented.
2. Maximum number of caches
The WebContent process has a maximum of two history stack caches, but the actual number of caches is determined by UIProcess. In UIProcess, WebProcessPool initializes WebBackForwardCache by setting the maximum number of caches, And when WebProcessProxy is created, the corresponding WebContent process is notified via IPC to set m_maxSize of BackForwardCache.
WebProcessPool’s WebBackForwardCache corresponds to each BackForwardCache singleton in the WebContent process pool, in a one-to-many mode. WebBackForwardCache will automatically trigger IPC notification to the WebContent process to clean the corresponding cache when pruning the cache element destructor:
WebBackForwardCacheEntry::~WebBackForwardCacheEntry() {
if (m_backForwardItemID && !m_suspendedPage) {
auto& process = this->process();
process.sendWithAsyncReply(Messages::WebProcess::ClearCachedPage(m_backForwardItemID), [] { });
}
}
Copy the code
So the maximum number of caches depends on the number of WebProcessPool. A WebProcessPool has a maximum of two history stack caches, regardless of how many WebContent its process pool has.
3. State synchronization
When the history stack cache state changes, the WebContent process calls notifyChanged() to synchronize the state via IPC notification to the corresponding WebBackForwardCache of UIProcess:
NotifyChanged () finally calls: static void WK2NotifyHistoryItemChanged(HistoryItem& item) { WebProcess::singleton().parentProcessConnection()->send(Messages::WebProcessProxy::UpdateBackForwardItem(toBackForwardLi stItemState(item)), 0); }Copy the code
Five, WKWebView common problems and solutions
A. The Request Body of the POST type is lost
Cause: After network interception is enabled, the request of the WebKit IPC process is transferred to the main process for execution. As the performance deteriorates due to process switchover, WebKit actively disallows the body of the request.
In NSURLProtocol subclass -startLoading is implemented by loading Request. HTTPBodyStream with Request. HTTPBody. But this approach sometimes fails (like Ajax);
2, through hook JS XMLHTTPRequest related methods. In particular, inject a SEND method with XHR requestType as POST to bridge the requstBody and the corresponding URL to the client. The client receives the data and saves it. In NSURLProtocol subclass – initWithRequest: cachedResponse: client: Method interception populates the requstBody stored on the client into the request to ensure that the requestBody is not lost;
B. White screen problem
Cause analysis: 1. WebContent Process crashes due to excessive memory usage. 2. WebContent process is suspended due to excessive memory usage.
Solution: 1, when WKWebView takes up too much memory, will lead to the WebContent process crash, the callback – webViewWebContentProcessDidTerminate:, You can add [webView reload] to this method and reload the page.
2, when WKWebView takes up too much memory (see more at select photo album), leads to the WebContent process was hung up, the situation will not invoke – webViewWebContentProcessDidTerminate:, In the WebViewController -viewwillAppear: method to detect whether webView.title exists, if not, it can be considered that the process is suspended, you can add [webView reload] in this method, reload the page to solve;
C, display HTML page is not the latest content
Cause analysis: WKWebView has cache;
Solution: To ensure that the latest page is loaded each time, add a timestamp after the loaded link;
D, the current page without navigation cannot fill the status bar (iOS11+ will lower the status bar height)
Cause analysis: When there is no navigation on the page, the system will automatically adjust the contentInset of the scroll view to keep the view under the status bar forever.
Solution:
If (@ the available (iOS 11.0, *)) { self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } else { // Fallback on earlier versions self.automaticallyAdjustsScrollViewInsets = NO; }Copy the code
-
1.BAT and other major manufacturers iOS interview questions + answers
-
2.Must-read books for Advanced Development in iOS (Classics must Read)
-
3.IOS Development Advanced Interview “resume creation” guide
-
(4)IOS Interview Process to the basics