WKWebViewTips
WKWebView Tips (iOS 8.1.0)
Install / Use
/learn @ShingoFukuyama/WKWebViewTipsREADME
This is what I learned about WKWebView, Apple's new WebKit API debuted on iOS 8.
As of this writing, the latest iOS version is iOS 8.1.3.
file:/// doesn't work without tmp directory
Only the tmp directory access can be accessed with the file: scheme, as of iOS 8.0.2.
You can see what directory access is allowed on the shazron / WKWebViewFIleUrlTest GitHut repo.
Note: On iOS 9.0.0 (beta), you can use the below method to load files from Documents, Library and tmp folders. But App Bundle cannot.
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
Can't handle in Storyboard and Interface Builder
You need to set WKWebView and any NSLayoutConstraints programmatically.
HTML <a> tag with target="_blank" won't respond
See Stack Overflow: Why is WKWebView not opening links with target=“_blank”
URL Scheme and App Store links won't work
Example
// Using [bendytree/Objective-C-RegEx-Categories](https://github.com/bendytree/Objective-C-RegEx-Categories) to check URL String
#import "RegExCategories.h"
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *url = navigationAction.request.URL;
NSString *urlString = (url) ? url.absoluteString : @"";
// iTunes: App Store link
if ([urlString isMatch:RX(@"\\/\\/itunes\\.apple\\.com\\/")]) {
[[UIApplication sharedApplication] openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
// Protocol/URL-Scheme without http(s)
else if (![urlString isMatch:[@"^https?:\\/\\/." toRxIgnoreCase:YES]]) {
[[UIApplication sharedApplication] openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
alert, confirm, prompt from JavaScript needs to set WKUIDelegate methods
If you want to show dialog boxes, you have to implement the following methods:
webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:
webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:
webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:
Basic/Digest/etc authentication input dialog boxes need to set a WKNavigationDelegate method
If you want to present an authentication challenge to user, you have to implement the method below:
webView:didReceiveAuthenticationChallenge:completionHandler:
Example:
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
NSString *hostName = webView.URL.host;
NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]
|| [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]
|| [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest]) {
NSString *title = @"Authentication Challenge";
NSString *message = [NSString stringWithFormat:@"%@ requires user name and password", hostName];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = @"User";
//textField.secureTextEntry = YES;
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = @"Password";
textField.secureTextEntry = YES;
}];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSString *userName = ((UITextField *)alertController.textFields[0]).text;
NSString *password = ((UITextField *)alertController.textFields[1]).text;
NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:userName password:password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}]];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:alertController animated:YES completion:^{}];
});
}
else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
// needs this handling on iOS 9
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
// or, see also http://qiita.com/niwatako/items/9ae602cb173625b4530a#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89
}
else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
Cookie sharing between multiple WKWebViews
Use a WKProcessPool to share cookies between web views.
Example:
self.processPool = [[WKProcessPool alloc] init];
WKWebViewConfiguration *configuration1 = [[WKWebViewConfiguration alloc] init];
configuration1.processPool = self.processPool;
WKWebView *webView1 = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration1];
...
WKWebViewConfiguration *configuration2 = [[WKWebViewConfiguration alloc] init];
configuration2.processPool = self.processPool;
WKWebView *webView2 = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration2];
...
See this Stack Overflow question.
Cannot work with NSURLProtocol, NSCachedURLResponse, NSURLProtocol
UIWebView can filter ad URLs and cache to read websites offline using NSURLProtocol, NSURLCache, and NSCachedURLResponse.
But WKWebView cannot work with those APIs.
Cookie, Cache, Credential, WebKit data cannot easily delete
iOS 8
After much trial and error, I've reached the following conclusion:
- Use
NSURLCacheandNSHTTPCookieto delete cookies and caches in the same way as you used to do onUIWebView. - If you use
WKProccessPool, re-initialize it. - Delete
Cookies,Caches,WebKitsubdirectories in theLibrarydirectory. - Delete all
WKWebViews
iOS 9
//// Optional data
NSSet *websiteDataTypes
= [NSSet setWithArray:@[
WKWebsiteDataTypeDiskCache,
WKWebsiteDataTypeOfflineWebApplicationCache,
WKWebsiteDataTypeMemoryCache,
WKWebsiteDataTypeLocalStorage,
WKWebsiteDataTypeCookies,
WKWebsiteDataTypeSessionStorage,
WKWebsiteDataTypeIndexedDBDatabases,
WKWebsiteDataTypeWebSQLDatabases
]];
//// All kinds of data
//NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
//// Date from
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
//// Execute
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
// Done
}];
Stack Overflow How to remove cache in WKWebview?
Scroll rate bug on iOS 9
On iOS 8, the below code works fine, it can scroll with more inertia.
webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
As for iOS 9, this code is meaningless, without setting the rate value within UIScrollView delegate scrollViewWillBeginDragging.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}
See Stack Overflow: Cannot change WKWebView's scroll rate on iOS 9
Cannot disable long press link menu
CSS: -webkit-touch-callout: none; and JavaScript: document.documentElement.style.webkitTouchCallout='none'; won't work.
Note: This bug was fixed in iOS 8.2.
Sometimes capturing WKWebView fails
Sometimes capturing a screenshot of WKWebView itself failed, try to capture WKWebView's scrollView property instead.
Otherwise, if you are not afraid of using private API, try lemonmojo/WKWebView-Screenshot.
Xcode 6.1 and above doesn't indicate precise memory usage for WKWebView
As of Xcode 6.1, it indicates lower memory usage than is actually used.
window.webkit.messageHandlers won't work on some websites
Some websites somehow override JavaScript's window.webkit. To prevent this issue, you should cache this to a variable before a website's content starts loading. WKUserScriptInjectionTimeAtDocumentStart can help you.
Cookie saving sometimes failed
Are cookies synced between NSHTTPCookie and WKWebView at some point?
Thanks to @winzig, he gives me information: "Cookie discussion / ajax #3"
See this Stack Overflow question: [Can I set the cookies to be used by a
Security Score
Audited on Feb 8, 2026
