WKWebView notes


IOS8 began, Apple introduced a new web control, WKWebView instead of UIWebView, WKWebView belongs to the WebKit framework, WebKit framework of API is very rich, you can start from WKWebView, one by one understanding. The WebKit framework is continually being updated, and iOS9, iOS, and 10 are introducing new API, and the trend is to get rid of UIWebView and use WKWebView. This article is to upgrade the project’s UIWebView experience and encountered some pits, hoping to help you.

1. brief introduction of WKWebView

A WKWebView is used to display interactive web content, just like a browser in APP. You can use WKWebView to embed web content in your APP.


This property is very important; js-> OC interacts entirely with it.

  • 1. dynamic injection of JS, the injection can be either JS code, can also be a JS file.
WKUserScript *script = [[WKUserScript, alloc], initWithSource:@, "alert" ("ha ha"); "injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO]; [controller addUserScript:script]";
  • 2.JavaScript sends messages to WKWebView by performing different native operations by identifying the contents of different messages and messages.
- - (void) addScriptMessageHandler: (ID < WKScriptMessageHandler>) scriptMessageHandler name: (NSString *) name;

Objects that follow the WKScriptMessageHandler protocol can receive messages sent by JavaScript in the following proxy methods.

- - (void) userContentController: (WKUserContentController *), userContentController, didReceiveScriptMessage: (WKScriptMessage *) message;


@property (nullable, nonatomic, copy), NSString, *customUserAgent, API_AVAILABLE (MacOSX (10.11), IOS (9));

Used to customize the browser UserAgent, but unfortunately, after 9 can be used, so, as with UIWebView, through the NSUserDefaults to set:

[[NSUserDefaults standardUserDefaults] registerDefaults:@{@ "UserAgent": newUserAgent}];

The 1.3. property supports KVO

Most of the properties of WKWebView support KVO, but there is no proxy method available, and you need to add your own monitor. For example, listening to title and estimatedProgress.

[self.wkWebView addObserver:self forKeyPath:@ "estimatedProgress" options:NSKeyValueObservingOptionNew context:nil] addObserver:self "title" [self.wkWebView; forKeyPath:@ options:NSKeyValueObservingOptionNew context:nil];

This shows the progress bar and does not have to wait until the web is fully loaded to display the title

- (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (ID) object change: (NSDictionary< NSKeyValueChangeKey, id> change (void * *) context: context{if ([keyPath) isEqualToString:@ "estimatedProgress"]) {CGFloat progress = [[change valueForKey:NSKeyValueChangeNewKey] floatValue]; if (Progress > = 1; [self.progressView) {setProgress:progress = animated:NO]; self.progressView.hidden YES; [self.progressView setProgress:0 animated:NO];} else {self.progressView.hidden = NO; [self.progressView setProgress:progress animated:YES];}} if ([keyPath isEqualToString:@ Title & & self.defaultTitle!) {NSString *title = [cha Nge valueForKey:NSKeyValueChangeNewKey]; if (title) {self.mTitleLabel.text = title;}}

Remember to delete the monitor

- (void) dealloc{NSLog (@ "% @", NSStringFromSelector (_cmd)); [self.wkWebView removeObserver:self context:nil]; forKeyPath:@ "estimatedProgress" [self.wkWebView removeObserver:self forKeyPath:@ "title context:nil]";}

1.4. identifies web content

Long press page, will pop up a UIActionSheet. For example, pressing a picture will prompt you to save your pictures. If you want to implement this function in UIWebView, you can only customize a gesture, and then get the contents of the page through JS, and then pop UIActionSheet.

WKWebView notes
identifies web content


The UIWebView call jsstringByEvaluatingJavaScriptFromString is returned synchronously and does not provide status information. WebKit is asynchronous block callback with state information. When using, be careful when the page is destroyed and the callback is made. The iOS8 will be on the crash.

- - (void) evaluateJavaScript: (NSString *), javaScriptString, completionHandler: (void (^ _Nullable) (_Nullable, ID, NSError * _Nullable, error)) completionHandler;

2. some pits

2.1.cookie problem

This should be the biggest WebKit pit, there is a lot of online article introduces the causes and solutions, I’m not superfluous, posted a link: cookie, I’m here to record the solution.
problem: the Cookie WKWebView loading page will be synchronized to the NSHTTPCookieStorage, but WKWebView has not loaded at the request of synchronization in NSHTTPCookieStorage Cookie, resulting in Cookie loss, web cannot identify the client identity.
solution: set the NSHTTPCookieStorage Cookie stored as the requested allHTTPHeaderFields, and write the Cookie into the web by injecting js.

Two point two

[5504:1981977] webViewWebContentProcessDidTerminate [5504:1982134] #WK: Unable to acquire assertion for process Could not signal service 0 [5504:1981977] com.apple.WebKit.WebContent: 113: Could not find specified service

This is often the case with analog slow networks, which are returned to 0 after a portion of the progress load. Debugging found that the creation of NSMutableURLRequest was caused by too short a set timeout. The solution is to increase timeout or simply do not set timeout.

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];

Two point three

When you’re testing on iOS9 iPod, it’s fine to enter a web page, but when you return, crash. The error message is as follows

2017-08-18 19:29:52.734 BluedInternational[11600:1646954] dealloc objc[11600] form weak reference to: Cannot instance (0x5225200) of class GJWebViewController. It is possible that this object was over-released, or is in the process of deallocation. (lldb) BT * thread #1, queue stop ='com.apple.main-thread', reason = EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xdefe) * frame #0: 0x20bf2a44 libobjc.A.dylib`_objc_trap (frame) #1: 0x20bf2aa8 libobjc.A.dylib` _objc_fatal (char, const*,...) + 72 frame #2: + 210 frame #3: 0x20c0c7b8 0x20c0c412 libobjc.A.dylib`weak_register_no_lock libobjc.A.dylib`objc_storeWeak frame #4: 0x25a8489a UIKit`-[UIScrollView + 208 setDelegate:] + 306 frame #5: 0x283c6f30 WebKit`- [WKScrollView _updateDelegate] frame #6: 0x283d09fe WebKit`-[WKWebView + 228 dealloc] + 266 frame #7: 0x20c0d3a8 libobjc.A.dylib` (anonymous namespace):: AutoreleasePoolPage:: Pop (void*) + 388 frame #8: + 16 frame #9: 0x2141806e 0x21366f88 CoreFoundation`_CFAutoreleasePoolPop CoreFoundation`__CFRunLoopRun frame #10: 0x21367228 + 1582 CoreFoundation`CFRunLoopRunSpecific + 520 frame #11: + 108 frame #12: 0x22957ac8 0x21367014 CoreFoundation`CFRunLoopRunInMode GraphicsServices`GSEventRunModal frame #13: 0x25a3b188 + 160 UIKit`UIApplicationMain + 144 frame #14: 0x0007cf62 BluedInternational`main (argc=1, argv=0x0361bab8) at main.m:13 frame #15: 0x2100f872 libdyld.dylib`start + 2 (lldb)

The analysis found that in the WKWebView release after unexpectedly also conducted scrollView proxy settings, but this time self, also is the current controller is destroyed, it explains the above mentioned log or is in the process of deallocation. So adding your WKWebView is lazy loading, do not set the proxy in lazy loads, and then nil the proxy in dealloc.

- (void) dealloc{NSLog (@ "% @", NSStringFromSelector (_cmd)); [self.wkWebView removeObserver:self context:nil]; forKeyPath:@ "estimatedProgress" [self.wkWebView removeObserver:self forKeyPath:@ "title" context:nil]; self.wkWebView.navigationDelegate = nil; self.wkWebView.UIDelegate = nil; self.wkWebView.scrollView.delegate = nil;}

Two point four

When iOS10 calls JS, crash is the following error message. This does not show where the error is. The APP has been deleted and reinstalled. If you have encountered the same problem, please generous with your criticism.

//2017-08-18 11:17:00.576568 [8132:2457446] Could not signal service com.apple.WebKit.Networking: 113: Could not find specified service (8132,0x1a8799c40) malloc: error / object 0x1700bf260: pointer being * * * for freed was not allocated set a breakpoint in malloc_error_break to //*** debug



Cookie is the web site user credentials information stored in the terminal for identification of terminal identity. The fields and meanings in Cookie are defined by the server. For example, when a user login operation on a website, the server will return Cookie information to the terminal, the terminal will save the information, visit the website again next time, the terminal will save Cookie information to be sent to the server, the server based on the Cookie information is effective to judge whether this user can automatically log on


A NSHTTPCookie instance represents a separate HTTP cookie that is initialized with the specified dictionary.

(nullable instancetype) - initWithProperties: (NSDictionary< NSHTTPCookiePropertyKey, id> properties; *) + (nullable * NSHTTPCookie) cookieWithProperties: (NSDictionary< NSHTTPCookiePropertyKey, id> * properties);


NSHTTPCookieStorage implements the management of shared a singleton object to the cookie storage, the client can increase, delete the object, get the current cookie, can also HTTP header field to parse and generate related cookie.

- (void) setCookie: (NSHTTPCookie * cookie); - (void) deleteCookie: (NSHTTPCookie *) cookie - (nullable NSArray< NSHTTPCookie; *> *) cookiesForURL: (NSURL *) URL; @property NSHTTPCookieAcceptPolicy cookieAcceptPolicy;


This class represents an authentication query message.
NSURLCredential stands for an authentication document.


MIME (Multipurpose Internet Mail Extensions) is the Internet standard that describes the type of message content.
MIME messages can contain text, images, audio, video, and other application specific data.
specific reference: MIME reference manual