Bad problems

So UIWebView, when it gets too much memory, the App crashes; WKWebView When the memory usage is too high, the WebContent process will crash, resulting in a blank screen. At this point, the URL of wkWebView becomes nil, and the reload operation is invalid.

Therefore, the root cause of the blank screen is App crash caused by excessive memory occupation, which is transformed into WebContent process crash.

The solution

WebViewWebContentProcessDidTerminate WKNavigationDelegate callback methods

Performs the webView reload operations in webViewWebContentProcessDidTerminate callback. This callback is triggered when the WebContent Process is about to go white. At this point, the URL of wkWebView has not yet become nil, so reload works. Interfaces with high memory consumption may be reloaded frequently.

Add a web content collapse process of the tag At the time of collapse webViewWebContentProcessDidTerminate set the tag, according to the tag in the viewWillAppear to judge, and then reload operations.

Use webview. url

When viewWillAppear, the URL is judged. If it is empty, it is reload.

Also use KVO to listen for empty URLS,

if ([self.webView.scrollView.superview isKindOfClass:[WKWebView class]]) { WKWebView *wkWebView = (WKWebView *)(self.webView.scrollView.superview); [wkWebView addObserver:self forKeyPath:@"URL" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"URL"]) { NSURL *newUrl = change[@"new"]; NSURL *oldUrl = change[@"old"]; if ([newUrl isEqual:[NSNull null]] && ! [oldUrl isEqual:[NSNull null]]) { [self.webView reload]; }}}Copy the code

Look at webview. title

Evaluate the title when viewWillAppear, and reload if it is empty.

Not all blank screen cases invoke the above callback method. If a camera is presented in the H5 interface and the Web content is suspended, the title of the wkWebView will be empty when the H5 interface is returned. If take photos consume too much memory, causing the memory tension, WebContent process hang up, but the above callback methods webViewWebContentProcessDidTerminate has not been called. WebView title is empty when the screen is white, so you can check webView.title is empty in viewWillAppear to reload the screen. Don’t understand?

Check this out with innerHTML

InnerHTML is evaluated when viewWillAppear, and reload if empty.

- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; __weak typeof(self) weakSelf = self; [self.webView evaluateJavaScript:@"document.querySelector('body').innerHTML" completionHandler:^(id result, NSError *error) { __strong __typeof(weakSelf) strongSelf = weakSelf; if (! The result | | ([result isKindOfClass: [nsstrings class]] && [((nsstrings *) result) length] = = 0)) {NSLog (@ "- H5 page load is unusual, Reload -- -- -- -- -- "); / / reload your page [strongSelf. WebView reload];} else {NSLog (@ "- H5 page load normal -- -- -- -- --");}}]; }Copy the code

Cookie problem

The question is:

Requests made by WKWebView do not automatically carry cookies stored in NSHTTPCookieStorage. And UIWebView will automatically take it.

Cookie format:

name=Nicholas; value=test; domain=y.qq.com; expires=Sat, 02 May 2019 23:38:25 GMT;Copy the code

UIWebView setting cookies

var props = Dictionary<HTTPCookiePropertyKey.Any>()
props[HTTPCookiePropertyKey.name] = "tigerobocookie"
props[HTTPCookiePropertyKey.value] = cookieValue // a string of key-values; Interval.
props[HTTPCookiePropertyKey.path] = "/"
props[HTTPCookiePropertyKey.domain] = API.tigerResearchWebDomain // Souyanbao.tigerobo.com must be set

if let cookie = HTTPCookie(properties: props) {
  NSHTTPCookieStorage.shared.setCookie(cookie)
}

xxx
let request = URLRequest(url: url)
webView.loadRequest(request)
Copy the code

WKWebView setting cookies

WKWebView doesn’t use NSHTTPCookieStorage.

Using WKWebView. Configuration. WebsiteDataStore httpCookieStore

guard let cookies = HTTPCookie(properties: props) else { return }
let httpCookieStore = wkWebView.configuration.websiteDataStore.httpCookieStore
httpCookieStore.setCookie(cookie) {
  DispatchQueue.main.async {
    self.wkWebView.load(request)
  }
}
Copy the code

But httpCookieStore is only available after iOS 11.

Before loadRequest, set a cookie in the request header to resolve the problem that the first cookie cannot be carried

NSURL *url = [NSURL URLWithString:@"http://github.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:@"skey=skeyValue" forHTTPHeaderField:@"Cookie"];

WKWebView *webView = [WKWebView new];
[webView loadRequest:request];
Copy the code

Cookie through document.cookie set cookie to solve the subsequent page (domain) Ajax, iframe request cookie problem

Note: Document.cookie () cannot set cookies across domains.

WKUserContentController *userContentController = [WKUserContentController new]; WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:@"document.cookie='skey=skeyValue'; " injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; [userContentController addUserScript:cookieScript];Copy the code

Cookie problem on request 302 cannot be resolved. Can be found in the webView: decidePolicyForNavigationAction: decisionHandler: callback methods intercept in 302 request, copy the request, Put cookies in the request header and reload the request. However, it still does not solve the cookie problem of page iframe spanning requests. Because loadRequest is only suitable for loading mainFrame requests.

NSURLProtocol can be used for man-in-the-middle attacks

WKWebView performs network requests independently of the webContent process outside of app and requests data without going through the main process. So WKWebView can’t directly use NSURLProtocol to intercept requests,

LoadRequest problem

The body of a POST request made by WKWebView via loadRequest will be lost. The HTTPBody field was discarded because of interprocess communication performance issues

[request setHTTPMethod:@"POST"];
[request setHTTPBody:[@"bodyData" dataUsingEncoding:NSUTF8StringEncoding]];
[wkWebView loadRequest:request];
Copy the code

That comes to mind

The key of performance optimization in small program development is the call of setData method. Why does this affect performance so much?

The view layer of the applet currently uses WebView as the rendering carrier, while the logic layer uses a separate JavascriptCore as the runtime environment. In terms of architecture, WebView and JavascriptCore are independent modules and do not have channels for direct data sharing.

Currently, data transfer between the view layer and the logical layer is actually implemented through evaluateJavascript provided on both sides. That is, the data transmitted by the user (from the view layer to the logic layer) needs to be converted into a string for transmission. Meanwhile, the converted data content is spliced into a JS script, and then transmitted to the independent environment on both sides by executing the JS script.

The evaluateJavascript execution is affected in many ways, and the arrival of data to the view layer is not real-time. Webviews within the same process actually share a JS VM, and if the JS thread within the WebView is performing rendering or other logic, this can affect the actual execution time of evaluateJavascript scripts,

In addition, multiple WebViews will preempt the execution permissions of the JS VM. In addition, the compilation and execution time of JS itself are factors affecting the data transmission speed.

Common setData errors:

  1. Execute setData frequently. Under Android, users will feel stuck when sliding, and the operation feedback delay is serious. There is a lag in rendering.
  2. Each time setData passes a lot of new data.
  3. Background state page for setData.

Why setData should be used:

Object attributes cannot be added or removed due to the limitations of the JS language. Unable to detect individual changes to data.

reference

  • WKWebView the pit
  • More than 70% of the business is developed by H5. How to optimize and evolve the structure of mobile QQ Hybrid?