2

Overview

Previously, UIWebView was mainly used for page loading, but UIWebView has many problems, and it has been officially abandoned by Apple in 2020. So this article mainly explains WKWebView , WKWebView from iOS8 , now most App should not support iOS7 .

UIWebView has two problems, one is that the memory consumption is relatively large, and the other is that the performance is poor. WKWebView with UIWebView UIWebView much better performance than 0617f513e201e7, and the refresh rate can reach 60FPS . The memory footprint is also smaller than UIWebView .

WKWebView is a multi-process component. Network and UI Render are all completed in independent processes.

Since WKWebView and App are not in the same process, if the WKWebView process crashes, it will not cause the application to crash. It is just an exception such as a blank page. Page loading, rendering and other operations that consume memory and performance are WKWebView , and after processing, the results are passed to the App for display, so the performance consumption of the process of App

Web page loading process

  1. Request the server by domain name, the browser will do a DNS resolution before requesting, and IP address of 0617f513e20331 to the browser.
  2. The browser uses the IP request the server and starts the handshake process. TCP is a three-way handshake. If you use https you also need to TLS a handshake of 0617f513e20371. After the handshake, you can choose whether to keep the connection according to the protocol field.
  3. After the handshake is completed, the browser sends a request to the server to obtain the html file.
  4. The server parses the request, and the CDN server returns the corresponding resource file.
  5. html file returned by the server and sends it to the html parser for analysis.
  6. When parsing html xml tag is parsed from top to bottom. During the process, if css or resource file is encountered, it will be loaded asynchronously. When js html parsing task will be suspended js and return to continue parsing. Because the js file may modify the DOM
  7. After parsing html and executing the js , the final DOM tree is formed. Find out the final display style of each node through DOM css file, and submit it to the browser for rendering and display
  8. End the link.

Proxy method

WKWebView and UIWebView have undergone some changes, and WKWebView has been more refined. For example, after UI ends the request, it will be rendered to webView immediately. WKWebView will call back a proxy method before rendering to the screen, and the proxy method determines whether to render to the screen. In this way, you can do a check on the requested data to prevent the data from being changed, or to verify whether the view is allowed to be displayed on the screen.

In addition, WKWebView has some more customized operations compared to UIWebView

  1. The redirection callback can get this operation when the redirection is requested.
  2. When the WKWebView process exits abnormally, it can be obtained through the callback.
  3. Customize the handling of certificates.
  4. The deeper UI custom operation, the alert operations such as UI , etc., are handed over to the native level for processing, and the UI scheme UIAlertView is directly displayed by webView

WKUIDelegate

WKWebView transfers a lot UI to the native level for processing, such as the display of pop-up windows or input boxes. In this way, if there is a uniformly defined pop-up window in the project, you can directly call the custom pop-up window instead of only displaying the system pop-up window.

In WKWebView , the system hands the display of the pop-up window to the client to control. The client can obtain the display information of the pop-up window through the following callback method, and the client can call UIAlertController to display it. There is a parameter completionHandler callback block , need to be sure to call the client, if you do not call it will crash.

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

Sometimes H5 will require the user to enter some input, such as username and password. The client can obtain the input box event through the following method, and the client displays the input box. After the user input is completed, the result will be completionHandler back to 0617f513e207b9.

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;

WKNavigationDelegate

The methods related to the loading process are abstracted into WKNavigationDelegate . Here are a few more commonly used methods to talk about.

The following method decisionHandler callback, which indicates whether the page is allowed to load. The domain name can be judged here, if it is an off-site domain name, the user can be prompted whether to redirect. If a jump is another App or store URL , you can openURL jump, and the request is intercepted. The processing including cookie is also completed in this method, and the processing cookie

In addition, many logical processing before the page is displayed are also completed in this method. But it should be noted that, do not do too much time-consuming processing in the method, which will affect the page loading speed.

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

Start loading the page and request the server.

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;

When the page fails to load, this method will be called back, including timeout such as 0617f513e208e4. On this page, you can display error pages, clear the progress bar, reset the network indicator, and other operations. It should be noted that this method will also be executed when goBack error by the status of NSURLErrorCancelled to determine whether it is 0617f513e208ea.

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error;

When the page is loaded and rendered, this method will be called. When this method is called, the H5 of dom has been parsed and rendered and displayed on the screen. So in this method, some loading operations can be performed, such as removing the progress bar, resetting the network indicator, and so on.

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;

WKUserContentController

Callback

The interactions between WKWebView and js WKUserContentController by 0617f513e209b1, which will be collectively referred to as userContent .

If you need to receive and process js call by calling addScriptMessageHandler:name: method, and pass a realization WKScriptMessageHandler the object of the agreement, can receive js callback, due userContent will be a strong reference to the object passed, so it should be to create a new object Instead of self . When registering an object, the following name is the name of the function called by js

WKUserContentController *userContent = [[WKUserContentController alloc] init];
[userContent addScriptMessageHandler:[[WKWeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"clientCallback"];

In dealloc , the following method should be used to remove the processing name

[userContent removeScriptMessageHandlerForName:@"clientCallback"];

H5 can initiate a call to the client through the following code. The call is to pass a json postMessage function, and the transfer character needs to be added. After the client receives the call, it obtains the body WKScriptMessage object passed in by the callback method, and then parses the passed parameters.

window.webkit.messageHandlers.clientCallback.postMessage("{\"funName\":\"getMobileCode\",\"value\":\"srggshqisslfkj\"}");

transfer

The method of calling H5 is the same, creating a WKUserScript object and passing in the js code as a parameter. In addition to calling the js , you can also inject code through this method to change the page dom , but this is a large amount of code and it is not recommended to do so.

WKUserScript *wkcookieScript = [[WKUserScript alloc] initWithSource:self.javaScriptString
                                                          injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                       forMainFrameOnly:NO];
[webView.configuration.userContentController addUserScript:wkcookieScript];

WKUserScript vs evaluateJavaScript

WKWebView for performing js code provides two ways, by userContent adding a WKUserScript embodiment the object, and by webView of evaluateJavaScript:completionHandler: embodiment, injection js code.

NSString *removeChildNode = @""
"var header = document.getElementsByTagName:('header')[0];"
"header.parentNote.removeChild(header);"
[self.webView evaluateJavaScript:removeChildNode completionHandler:nil];

The first thing to note is that both methods can inject the js code, but I haven't studied its internal implementation in depth. The WebKit kernel is open source, and interested students can take a look. However, there are still some functional differences between the two methods. The API

Let me talk about the evaluateJavaScript:completionHandler: method. This method is generally performed after the page is displayed js and get the return value. Of course, it can also be used to inject a section of js code, but you need to control the injection timing yourself.

WKUserScript can control the timing of injection. You can js document whether 0617f513e20c54 is loaded or not. And whether the injected js is valid on the current page or including its subpages. Compared with the evaluateJavaScript: method, this method cannot get js , so the two methods are still different in function.

Container design

Design ideas

WKWebView is not used directly in the project, but through a layer of packaging, it becomes a WKWebViewController handed over to the business layer for use. When designing webViewVC , you should follow a simple and flexible design. It only provides display functions and does not involve any business logic. It provides external functions such as displaying the navigation bar, setting the title, and the progress bar, which can be assigned WKWebViewConfiguration and passed in when WKWebViewController

js interaction, webView life cycle, loading error, etc. to the caller, and the external connection is handled through the corresponding callback. These callbacks are optional, and if they are not implemented, the webView will not be affected. The following is an example code, you can also split different types of callbacks to define different agents.

@protocol WKWebViewControllerDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(WKWebViewController *)webViewVC;
- (void)webViewDidFinishLoad:(WKWebViewController *)webViewVC;
- (void)webView:(WKWebViewController *)webViewVC didFailLoadWithError:(NSError *)error;
- (void)webview:(WKWebViewController *)webViewVC closeWeb:(NSString *)info;
- (void)webview:(WKWebViewController *)webViewVC login:(NSDictionary *)info;
- (void)webview:(WKWebViewController *)webViewVC jsCallbackParams:(NSDictionary *)params;
@end

In addition, WKWebViewController should also be responsible for handling public parameters, and can be extended based on public parameters. Here we define a method that can specify the position of the basic parameters, which is added by URL splicing, header , js injection, etc. This enumeration is multi-selected, that is, it can be injected at multiple locations. In addition to the basic parameters, you can also add custom parameters, which will also be added to the specified location.

- (void)injectionParamsType:(SVParamsType)type additionalParams:(NSDictionary *)additionalParams;

Reuse pool

WKWebView initialized for the first time, it will start the webKit kernel first, and there are some initialization operations, this operation is very performance-consuming. Therefore, the first step in the design of the reuse pool is to initialize a global WKWebView App started.

And, create two pools, create visiblePool store the in-use ones, and create reusablePool store the idle state. In addition, when the page exits, the page should be recycled and the data on the page should be reclaimed while loading visiblePool reusablePool

When you need to initialize a webView container, reusablePool and put it into visiblePool . Through the realization of the reuse pool, the time from initializing a webView container to displaying the page can be reduced.

WKProcessPool

In WKWebView defined in processPool property, you can specify the corresponding process pool object. Each webView has its own content process, if not specified, it will default to a new content process. The content process includes some local cookie , resources, etc. If they are not in a content process, these data cannot be shared.

You can create a public WKProcessPool , which is a singleton object. When all webView created, they use the same content process to realize resource sharing.

UserAgent

User-Agent is a request header field in the http protocol to inform the server of some information. User-Agent contains many fields, such as system version, browser kernel version, network environment, etc. This field can be directly provided by the system, or other fields can be added on the basis of the User-Agent

For example, the following is webView obtained User-Agent .

Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89

In iOS9 after providing a customUserAgent property directly WKWebView provided User-Agent , and iOS9 required by prior js to embodiment writing H5 injection User-Agent .

letter of agreement

A well-designed WebView container should have good mutual communication functions, and be flexible and expandable. H5 and the client mainly has the following scenarios.

  • js calls the client, and js calls the client to get the client's callback callback and parameters.
  • The client calls js and callback callback and parameters after js
  • The client proactively notified H5 of some changes in the client's life cycle. For example, enter the lock screen and enter the system life cycle of the front desk.

Taking js call the client as an example, there are two latitude calls. You can URLRouter , which can be called up by following the client's URL definition, and it supports parameter transfer. You can also make page-level calls userContentController webView , calling up the login function, etc., that is, js . This method requires the client to provide the corresponding processing code.

Call each other between the two, try to avoid high-frequency calls, and generally there is no need for high-frequency calls. However, if a high-frequency call of the same function occurs, you need to set a actionID to distinguish different calls to ensure that they can be distinguished normally when a callback occurs.

callback can also be passed through parameters. This method is more flexible. If it is fixed, there will be version restrictions. Earlier versions of the client may not support this callback.

Handle callback

In addition to the basic calls of webView refresh refreshing the current page, close closing the current page, etc., the call is directly handled by the corresponding function class, and the other time should be handed over to the outside for processing.

The design scheme here is not that one event corresponds to one callback method, and then the outside world follows the proxy and implements multiple proxy methods. Instead, each callback event is encapsulated into an object, and this object is directly called back to the outside world for processing, so that it is more flexible and the outside world can obtain more information. The definition of the event model can refer to the following.

@interface WKWebViewCallbackModel : NSObject
@property(nonatomic, strong) WKWebViewController *webViewVC;
@property(nonatomic, strong) WKCallType *type;
@property(nonatomic, copy) NSDictionary *parameters;
@property(nonatomic, copy) NSString *callbackID;
@property(nonatomic, copy) NSString *callbackFunction;
@end

Persistence

Currently H5 persistence solution pages, mainly WebKit comes localStorage and Cookie , but Cookie not used for persistence operations, it should not be given H5 used for persistence. If you want to be more stable persistence, you may consider providing a js bridge of CRUD interface that allows H5 can be used to store and query data.

The persistence solution adopts the same solution as the client, and a separate data table can be H5

Caching mechanism

Caching rules

Front-end browsers, including WKWebView , will cache resources in order to ensure quick page opening and reduce user traffic consumption. This caching rule WKWebView . If we want to ensure that the resource files are up-to-date each time, we can also choose not to use the cache, but we generally don't do this.

  • NSURLRequestUseProtocolCachePolicy = 0 , the default cache strategy, is the same as the cache performance of the Safari
  • NSURLRequestReloadIgnoringLocalCacheData = 1, ignores the local cache and obtains data directly from the server.
  • NSURLRequestReturnCacheDataElseLoad = 2 , if there is a local cache, use the cache, otherwise load the server data. This strategy does not verify whether the cache expires.
  • NSURLRequestReturnCacheDataDontLoad = 3 , only obtained from the local, and does not judge the validity and whether it is changed. If there is no local, the server data will not be requested, and the request will fail.
  • NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4 , ignoring the local and routing caches, and get the latest data from the server.
  • NSURLRequestReloadRevalidatingCacheData = 5 , verify that the cache is available from the server, and request data from the server if it is not available locally.
  • NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,

15993877718102.jpg

According to Apple's default caching strategy, a three-step check will be performed.

  1. Whether the cache exists.
  2. Verify that the cache is out of date.
  3. Whether the cache has changed.

Cache file

iOS9 Apple provides the cache management class WKWebsiteDataStore , which can query and delete the specified type of cache files on the disk. Because many App are iOS9 , it is highly recommended to use this API to manage the local cache, as well as cookie . The local file cache types are defined as the following, the commonly used ones are mainly cookie , diskCache , memoryCache .

  • WKWebsiteDataTypeFetchCache , the cache in the disk, according to the source code, the type is DOMCache
  • WKWebsiteDataTypeDiskCache , the local disk cache, which is different from the implementation of fetchCache
  • WKWebsiteDataTypeMemoryCache , local memory cache
  • WKWebsiteDataTypeOfflineWebApplicationCache , offline web application cache
  • WKWebsiteDataTypeCookies , cookie cache
  • WKWebsiteDataTypeSessionStorage , html session storage
  • WKWebsiteDataTypeLocalStorage , html local data cache
  • WKWebsiteDataTypeWebSQLDatabases , WebSQL database data
  • WKWebsiteDataTypeIndexedDBDatabases , database index
  • WKWebsiteDataTypeServiceWorkerRegistrations , server registration data

You can get all the local cache file types through the following method, and the returned collection string is the type defined above.

+ (NSSet<NSString *> *)allWebsiteDataTypes;

You can specify to delete the specified type of data within a certain period of time, and the callback will be block after deletion.

- (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler;

The system also provides a more customized method. Obtain all WKWebsiteDataRecord fetchDataRecordsOfTypes: method. This object contains two parameters: domain name and type. You can judge based on the domain name and type, and then call the removeDataOfTypes: method to pass in the object to be deleted, and delete the data under the specified domain name.

// 获取
- (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler;
// 删除
- (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler;

http caching strategy

When the client H5 , page caching problems often occur. H5 often say "try to clear the cache". In fact, the reason for this problem is that there is a problem with the cache management strategy H5 Here to talk about the cache management strategy of H5

The cache management of H5 http protocol. The more commonly used method is the Cache-Control and Last-Modified .

  • Cache-Control : The effective duration of the file cache. For example, the server response header returns Cache-Control:max-age=600 after requesting the file, which means that the effective duration of the file is 600 seconds. Therefore, this file will not issue a network request within the validity period until it expires.
  • Last-Modified : The response header returned by the server after requesting the file indicates the latest update time of the file. If Cache-Control expires, it will request the server and put this time in the If-Modified-Since field of the request header. The server will compare the time after receiving the request. If the time has not changed, it will return 304 , otherwise it will return a new file and response header field. , And return 200 .

Cache-Control is from http1.1 , indicating the relative effective duration of the file. Before this, there is a Expires , indicating the absolute effective duration of the file, for example, Expires: Thu, 10 Nov 2015 08:45:11 GMT , both of which can be used.

Last-Modified also has a similar field Etag , the difference is that Last-Modified is compared with the time, and Etag is compared with the hash value of the file. When the validity period of the file expires, the requesting server will Etag If-None-Match field of the request header and submit it to the server for comparison.

Cookie handling

As we all know, the http protocol supports the cookie . The server can set the browser to cookie Set-Cookie: field, and can also specify the expiration time, domain name, etc. These are more applicable in browsers such as Chrome , but if it is displayed in the client, the client needs to pass some parameters, so that H5 can get the login status.

Although Apple provides some Cookie managed by API , there WKWebView in the use of 0617f513e34576. Finally, I will give a more general solution.

WKWebView Cookie Design

When using UIWebView before, it reads an area with the traditional cookie management class NSHTTPCookieStorage UIWebView of cookie is also managed by this class. However, the WKWebView cookie not the same. cookie App of 0617f513e345e1, so the two need to be processed separately.

WKWebView of cookie and NSHTTPCookieStorage also between synchronous operation, but the synchronization significant delay, but not easy to rule pondering. So for the stability of the code, it is more appropriate to cookie

WK and app are two processes, cookie is two, but WK of cookie in app sandbox of. There is a timing synchronization, but there is no specific rule, so it is best not to rely on synchronization. WK are only two opportunities for the cookie change of 0617f513e3580f, one is for js execute code setCookie , and the other is for response to return to cookie .

WKWebsiteDataStore

Cookie management has always been WKWebView a drawback, for the Cookie inconvenient process. In iOS9 , you can Cookie WKWebsiteDataStore , but it is not intuitive to use, you need to filter and delete dataType Moreover, WKWebsiteDataStore does not have the function of adding, so cookie can only be deleted, and cookie cannot be added.

if (@available(iOS 9.0, *)) {
    NSSet *cookieTypeSet = [NSSet setWithObject:WKWebsiteDataTypeCookies];
    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:cookieTypeSet modifiedSince:[NSDate dateWithTimeIntervalSince1970:0] completionHandler:^{
        
    }];
}

WKHTTPCookieStore

In iOS11 in Apple WKWebsiteDataStore based on its increased WKHTTPCookieStore class specifically cookie processing, and support for add, delete, query three operations, you can also register a observer to cookie changes to monitor, when cookie after change Notify the listener through the callback method.

WKWebsiteDataStore can get H5 page by document.cookie way of writing cookie , as well as a server by Set-Cookie way of writing cookie , so it is still very recommended to use this class to manage cookie , but unfortunately only supports iOS11 .

Below is a piece of code to add cookie WKWebView

NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:@"password" forKey:NSHTTPCookieName];
[params setObject:@"e10adc3949ba5" forKey:NSHTTPCookieValue];
[params setObject:@"www.google.com" forKey:NSHTTPCookieDomain];
[params setObject:@"/" forKey:NSHTTPCookiePath];
[params setValue:[NSDate dateWithTimeIntervalSinceNow:60*60*72] forKey:NSHTTPCookieExpires];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:params];
[self.cookieWebview.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];

My company plan

Processing Cookie best way is through WKHTTPCookieStore to deal with, but it only supports iOS11 and more equipment, so this program is still not as our choice. The second is WKWebsiteDataStore , but it can only be used as a delete cookie , and it cannot be used to manage cookie .

Our approach is that by iOS8 launched WKUserContentController to manage webView of cookie by NSHTTPCookieStorage to manage network requests cookie , for example H5 request made. NSURLConnection sent through NSURLSession and 0617f513e36308 will default to NSHTTPCookieStorage in cookie , and H5 within 0617f513e3630e will also be handed over to NSURLSession by the system for processing.

At the level of code implementation, monitor the didFinishLaunching notification, and request user-related information from the server when the program starts. Of course, it can also be taken locally, all of which are the same. Data are key , value issued form according key=value form of stitching, by document.cookie assembled into a set cookie of js codes, all the code string of splicing a semicolon separated, behind to webView species cookie time to time by the character String execution.

cookie requested by the network, if you use NSHTTPCookieStorage directly transfer cookie to the root domain name, it can take effect for all subdomains under the root domain name. The processing here is relatively simple.

SVREQUEST.type(SVRequestTypePost).parameters(params).success(^(NSDictionary *cookieDict) {
    self.cookieData = [cookieDict as:[NSDictionary class]];
    [self addCookieWithDict:cookieDict forHost:@".google.com"];
    [self addCookieWithDict:cookieDict forHost:@".google.cn"];
    [self addCookieWithDict:cookieDict forHost:@".google.jp"];
    
    NSMutableString *scriptString = [NSMutableString string];
    for (NSString *key in self.cookieData.allKeys) {
        NSString *cookieString = [NSString stringWithFormat:@"%@=%@", key, cookieDict[key]];
        [scriptString appendString:[NSString stringWithFormat:@"document.cookie = '%@;expires=Fri, 31 Dec 9999 23:59:59 GMT;';", cookieString]];
    }
    self.webviewCookie = scriptString;
}).startRequest();

- (void)addCookieWithDict:(NSDictionary *)dict forHost:(NSString *)host {
    [dict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull value, BOOL * _Nonnull stop) {
        NSMutableDictionary *properties = [NSMutableDictionary dictionary];
        [properties setObject:key forKey:NSHTTPCookieName];
        [properties setObject:value forKey:NSHTTPCookieValue];
        [properties setObject:host forKey:NSHTTPCookieDomain];
        [properties setObject:@"/" forKey:NSHTTPCookiePath];
        [properties setValue:[NSDate dateWithTimeIntervalSinceNow:60*60*72] forKey:NSHTTPCookieExpires];
        NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    }];
}

Of webView species cookie by WKUserContentController writing js embodiment implemented, i.e. splicing above js string. But this class has a persistent problem that can not cookie , which is cookie with userContentController statement cycle, if the exit App the cookie will disappear next time you enter App need species also once, which is a big problem.

Therefore, our company's processing method is decidePolicyForNavigationAction: callback method. The code will determine whether the domain name has been seeded with cookie , if not, type cookie . For cookie process, I created a new cookieWebview deal specifically cookie problems when performing addUserScript later, by loadHTMLString:baseURL: load an empty local html , and domain name to be currently the domain name of the page, so that just kind of cookie current processPool all within webView effect.

This kind of scheme cookie is executed synchronously, and has webView impact on 0617f513e36540. After my test, adding cookie average only takes 28ms time. From the user's point of view, it is imperceptible, and there will be no page freeze or refresh.

- (void)setCookieWithUrl:(NSURL *)url {
    NSString *host = [url host];
    if ([self.cookieURLs containsObject:host]) {
        return;
    }
    [self.cookieURLs addObject:host];
    
    WKUserScript *wkcookieScript = [[WKUserScript alloc] initWithSource:self.webviewCookie
                                                          injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                       forMainFrameOnly:NO];
    [self.cookieWebview.configuration.userContentController addUserScript:wkcookieScript];
    
    NSString *baseWebUrl = [NSString stringWithFormat:@"%@://%@", url.scheme, url.host];
    [self.cookieWebview loadHTMLString:@"" baseURL:[NSURL URLWithString:baseWebUrl]];
}

The process of deleting cookie is relatively simple. NSHTTPCookieStorage traverses through the cookies NSHTTPCookie that you need to delete, and then you can delete it by calling the method. webView is simple and rude, just call removeAllUserScripts delete all WKUserScript .

- (void)removeWKWebviewCookie {
    self.webviewCookie = nil;
    [self.cookieWebview.configuration.userContentController removeAllUserScripts];
    
    NSMutableArray<NSHTTPCookie *> *cookies = [NSMutableArray array];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull cookie, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([self.cookieData.allKeys containsObject:cookie.name]) {
            [cookies addObjectOrNil:cookie];
        }
    }];
    
    [cookies enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull cookie, NSUInteger idx, BOOL * _Nonnull stop) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }];
}

White screen problem

If WKWebView loads a page that takes up too much memory, it will cause the WebContent Process process to crash, and then a white screen will appear on the page. It may also be caused by other processes in the system occupying too much memory. There are two solutions to the white screen problem caused by low memory.

In iOS9 , Apple introduced the following API . When the WebContent process exits abnormally, it will call back this API . Corresponding processing can be performed in this API , such as displaying an abnormal page.

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;

If returning from other App causes a white screen problem, you can judge whether webView.title is empty when the view is about to be displayed. If it is empty, the abnormal page will be displayed.


刘小壮
396 声望820 粉丝

向着星辰大海的征途,去到那别人连梦想都未曾抵达的地方!