Optimize WKWebView click behavior

If your app utilizes WKWebView to display web content, you might want to consider optimizing click behavior for the following reasons:

  • WKWebView doesn't support tabbed browsing. Ad clicks that attempt to open a new tab do nothing by default.
  • Ad clicks that open in the same tab reload the page. You might want to force ad clicks to open outside the WKWebView , for example if you host H5 games and want to maintain the state of each game.

  • AutoFill doesn't support credit card information in WKWebView . This could lead to less ecommerce conversions for advertisers, negatively affecting the web content's monetization.

This guide provides recommended steps to optimize the click behavior in mobile web views while preserving the web view content.

Prerequisites

Implementation

Ad links can have the href target attribute set to either _blank , _top , _self , or _parent . Ad links can also contain JavaScript functions such as window.open(url, "_blank") .

The following table describes how each of these links behave in a web view.

href target attribute Default WKWebView click behavior
target="_blank" Link not handled by the web view.
target="_top" Reload link in the existing web view.
target="_self" Reload link in the existing web view.
target="_parent" Reload link in the existing web view.
JavaScript function Default WKWebView click behavior
window.open(url, "_blank") Link not handled by the web view.

Follow these steps to optimize the click behavior in your WKWebView instance:

  1. Set the WKUIDelegate on your WKWebView instance.

  2. Set the WKNavigationDelegate on your WKWebView instance.

  3. Determine whether to optimize the behavior of the click URL.

    • Check if the navigationType property on the WKNavigationAction object is a click type you want to optimize. The code example checks for .linkActivated which only applies to clicks on a link with an href attribute.

    • Check the targetFrame property on the WKNavigationAction object. If it returns nil , it means the target of the navigation is a new window. Since WKWebView can't handle that click, these clicks must be handled manually.

  4. Decide whether to open the URL in an external browser, SFSafariViewController , or the existing web view. The code snippet shows how to open URLs navigating away from the site by presenting a SFSafariViewController .

Code example

The following code snippet shows how to optimize the web view click behavior. As an example, it checks if the current domain is different than the target domain. This is just one approach as the criteria you use could vary.

Swift

  import 
  
 GoogleMobileAds 
 import 
  
 SafariServices 
 import 
  
 WebKit 
 class 
  
 ViewController 
 : 
  
 UIViewController 
 , 
  
 WKNavigationDelegate 
 , 
  
 WKUIDelegate 
  
 { 
  
 override 
  
 func 
  
 viewDidLoad 
 () 
  
 { 
  
 super 
 . 
 viewDidLoad 
 () 
  
 // ... Register the WKWebView. 
  
 // 1. Set the WKUIDelegate on your WKWebView instance. 
  
 webView 
 . 
 uiDelegate 
  
 = 
  
 self 
 ; 
  
 // 2. Set the WKNavigationDelegate on your WKWebView instance. 
  
 webView 
 . 
 navigationDelegate 
  
 = 
  
 self 
  
 } 
  
 // Implement the WKUIDelegate method. 
  
 func 
  
 webView 
 ( 
  
 _ 
  
 webView 
 : 
  
 WKWebView 
 , 
  
 createWebViewWith 
  
 configuration 
 : 
  
 WKWebViewConfiguration 
 , 
  
 for 
  
 navigationAction 
 : 
  
 WKNavigationAction 
 , 
  
 windowFeatures 
 : 
  
 WKWindowFeatures 
 ) 
  
 - 
>  
 WKWebView 
 ? 
  
 { 
  
 // 3. Determine whether to optimize the behavior of the click URL. 
  
 if 
  
 didHandleClickBehavior 
 ( 
  
 currentURL 
 : 
  
 webView 
 . 
 url 
 , 
  
 navigationAction 
 : 
  
 navigationAction 
 ) 
  
 { 
  
 print 
 ( 
 "URL opened in SFSafariViewController." 
 ) 
  
 } 
  
 return 
  
 nil 
  
 } 
  
 // Implement the WKNavigationDelegate method. 
  
 func 
  
 webView 
 ( 
  
 _ 
  
 webView 
 : 
  
 WKWebView 
 , 
  
 decidePolicyFor 
  
 navigationAction 
 : 
  
 WKNavigationAction 
 , 
  
 decisionHandler 
 : 
  
 @ 
 escaping 
  
 ( 
 WKNavigationActionPolicy 
 ) 
  
 - 
>  
 Void 
 ) 
  
 { 
  
 // 3. Determine whether to optimize the behavior of the click URL. 
  
 if 
  
 didHandleClickBehavior 
 ( 
  
 currentURL 
 : 
  
 webView 
 . 
 url 
 , 
  
 navigationAction 
 : 
  
 navigationAction 
 ) 
  
 { 
  
 return 
  
 decisionHandler 
 (. 
 cancel 
 ) 
  
 } 
  
 decisionHandler 
 (. 
 allow 
 ) 
  
 } 
  
 // Implement a helper method to handle click behavior. 
  
 func 
  
 didHandleClickBehavior 
 ( 
  
 currentURL 
 : 
  
 URL 
 , 
  
 navigationAction 
 : 
  
 WKNavigationAction 
 ) 
  
 - 
>  
 Bool 
  
 { 
  
 guard 
  
 let 
  
 targetURL 
  
 = 
  
 navigationAction 
 . 
 request 
 . 
 url 
  
 else 
  
 { 
  
 return 
  
 false 
  
 } 
  
 // Handle custom URL schemes such as itms-apps:// by attempting to 
  
 // launch the corresponding application. 
  
 if 
  
 navigationAction 
 . 
 navigationType 
  
 == 
  
 . 
 linkActivated 
  
 { 
  
 if 
  
 let 
  
 scheme 
  
 = 
  
 targetURL 
 . 
 scheme 
 , 
  
 ! 
 [ 
 "http" 
 , 
  
 "https" 
 ]. 
 contains 
 ( 
 scheme 
 ) 
  
 { 
  
 UIApplication 
 . 
 shared 
 . 
 open 
 ( 
 targetURL 
 , 
  
 options 
 : 
  
 [:], 
  
 completionHandler 
 : 
  
 nil 
 ) 
  
 return 
  
 true 
  
 } 
  
 } 
  
 guard 
  
 let 
  
 currentDomain 
  
 = 
  
 currentURL 
 . 
 host 
 , 
  
 let 
  
 targetDomain 
  
 = 
  
 targetURL 
 . 
 host 
  
 else 
  
 { 
  
 return 
  
 false 
  
 } 
  
 // Check if the navigationType is a link with an href attribute or 
  
 // if the target of the navigation is a new window. 
  
 if 
  
 ( 
 navigationAction 
 . 
 navigationType 
  
 == 
  
 . 
 linkActivated 
  
 || 
  
 navigationAction 
 . 
 targetFrame 
  
 == 
  
 nil 
 ) 
  
&&  
 // If the current domain does not equal the target domain, 
  
 // the assumption is the user is navigating away from the site. 
  
 currentDomain 
  
 != 
  
 targetDomain 
  
 { 
  
 // 4. Open the URL in a SFSafariViewController. 
  
 let 
  
 safariViewController 
  
 = 
  
 SFSafariViewController 
 ( 
 url 
 : 
  
 targetURL 
 ) 
  
 present 
 ( 
 safariViewController 
 , 
  
 animated 
 : 
  
 true 
 ) 
  
 return 
  
 true 
  
 } 
  
 return 
  
 false 
  
 } 
 } 
 

Objective-C

  @import 
  
 GoogleMobileAds 
 ; 
 @import 
  
 SafariServices 
 ; 
 @import 
  
 WebKit 
 ; 
 @interface 
 ViewController 
  
 () 
  
< WKNavigationDelegate 
 , 
  
 WKUIDelegate 
> @property 
 ( 
 nonatomic 
 , 
  
 strong 
 ) 
  
 WKWebView 
  
 * 
 webView 
 ; 
 @end 
 @implementation 
 ViewController 
 - 
 ( 
 void 
 ) 
 viewDidLoad 
  
 { 
  
 [ 
 super 
  
 viewDidLoad 
 ]; 
  
 // ... Register the WKWebView. 
  
 // 1. Set the WKUIDelegate on your WKWebView instance. 
  
 self 
 . 
 webView 
 . 
 uiDelegate 
  
 = 
  
 self 
 ; 
  
 // 2. Set the WKNavigationDelegate on your WKWebView instance. 
  
 self 
 . 
 webView 
 . 
 navigationDelegate 
  
 = 
  
 self 
 ; 
 } 
 // Implement the WKUIDelegate method. 
 - 
 ( 
 WKWebView 
  
 * 
 ) 
 webView: 
 ( 
 WKWebView 
  
 * 
 ) 
 webView 
  
 createWebViewWithConfiguration 
 :( 
 WKWebViewConfiguration 
  
 * 
 ) 
 configuration 
  
 forNavigationAction 
 :( 
 WKNavigationAction 
  
 * 
 ) 
 navigationAction 
  
 windowFeatures 
 :( 
 WKWindowFeatures 
  
 * 
 ) 
 windowFeatures 
  
 { 
  
 // 3. Determine whether to optimize the behavior of the click URL. 
  
 if 
  
 ([ 
 self 
  
 didHandleClickBehaviorForCurrentURL 
 : 
  
 webView 
 . 
 URL 
  
 navigationAction 
 : 
  
 navigationAction 
 ]) 
  
 { 
  
 NSLog 
 ( 
 @"URL opened in SFSafariViewController." 
 ); 
  
 } 
  
 return 
  
 nil 
 ; 
 } 
 // Implement the WKNavigationDelegate method. 
 - 
 ( 
 void 
 ) 
 webView: 
 ( 
 WKWebView 
  
 * 
 ) 
 webView 
  
 decidePolicyForNavigationAction 
 :( 
 WKNavigationAction 
  
 * 
 ) 
 navigationAction 
  
 decisionHandler 
 : 
  
 ( 
 void 
  
 ( 
 ^ 
 )( 
 WKNavigationActionPolicy 
 )) 
 decisionHandler 
  
 { 
  
 // 3. Determine whether to optimize the behavior of the click URL. 
  
 if 
  
 ([ 
 self 
  
 didHandleClickBehaviorForCurrentURL 
 : 
  
 webView 
 . 
 URL 
  
 navigationAction 
 : 
  
 navigationAction 
 ]) 
  
 { 
  
 decisionHandler 
 ( 
 WKNavigationActionPolicyCancel 
 ); 
  
 return 
 ; 
  
 } 
  
 decisionHandler 
 ( 
 WKNavigationActionPolicyAllow 
 ); 
 } 
 // Implement a helper method to handle click behavior. 
 - 
 ( 
 BOOL 
 ) 
 didHandleClickBehaviorForCurrentURL: 
 ( 
 NSURL 
  
 * 
 ) 
 currentURL 
  
 navigationAction 
 :( 
 WKNavigationAction 
  
 * 
 ) 
 navigationAction 
  
 { 
  
 NSURL 
  
 * 
 targetURL 
  
 = 
  
 navigationAction 
 . 
 request 
 . 
 URL 
 ; 
  
 // Handle custom URL schemes such as itms-apps:// by attempting to 
  
 // launch the corresponding application. 
  
 if 
  
 ( 
 navigationAction 
 . 
 navigationType 
  
 == 
  
 WKNavigationTypeLinkActivated 
 ) 
  
 { 
  
 NSString 
  
 * 
 scheme 
  
 = 
  
 targetURL 
 . 
 scheme 
 ; 
  
 if 
  
 ( 
 ! 
 [ 
 scheme 
  
 isEqualToString 
 : 
 @"http" 
 ] 
 && 
 ! 
 [ 
 scheme 
  
 isEqualToString 
 : 
 @"https" 
 ]) 
  
 { 
  
 [ 
 UIApplication 
 . 
 sharedApplication 
  
 openURL 
 : 
 targetURL 
  
 options 
 : 
 @{} 
  
 completionHandler 
 : 
 nil 
 ]; 
  
 return 
  
 YES 
 ; 
  
 } 
  
 } 
  
 NSString 
  
 * 
 currentDomain 
  
 = 
  
 currentURL 
 . 
 host 
 ; 
  
 NSString 
  
 * 
 targetDomain 
  
 = 
  
 targetURL 
 . 
 host 
 ; 
  
 if 
  
 ( 
 ! 
 currentDomain 
  
 || 
  
 ! 
 targetDomain 
 ) 
  
 { 
  
 return 
  
 NO 
 ; 
  
 } 
  
 // Check if the navigationType is a link with an href attribute or 
  
 // if the target of the navigation is a new window. 
  
 if 
  
 (( 
 navigationAction 
 . 
 navigationType 
  
 == 
  
 WKNavigationTypeLinkActivated 
  
 || 
  
 ! 
 navigationAction 
 . 
 targetFrame 
 ) 
  
 // If the current domain does not equal the target domain, 
  
 // the assumption is the user is navigating away from the site. 
 && 
 ! 
 [ 
 currentDomain 
  
 isEqualToString 
 : 
  
 targetDomain 
 ]) 
  
 { 
  
 // 4. Open the URL in a SFSafariViewController. 
  
 SFSafariViewController 
  
 * 
 safariViewController 
  
 = 
  
 [[ 
 SFSafariViewController 
  
 alloc 
 ] 
  
 initWithURL 
 : 
 targetURL 
 ]; 
  
 [ 
 self 
  
 presentViewController 
 : 
 safariViewController 
  
 animated 
 : 
 YES 
  
 completion 
 : 
 nil 
 ]; 
  
 return 
  
 YES 
 ; 
  
 } 
  
 return 
  
 NO 
 ; 
 } 
 

Test your page navigation

To test your page navigation changes, load

  https://google.github.io/webview-ads/test/#click-behavior-tests 
 

into your web view. Click each of the different link types to see how they behave in your app.

Here are some things to check:

  • Each link opens the intended URL.
  • When returning to the app, the test page's counter doesn't reset to zero to validate the page state was preserved.
Create a Mobile Website
View Site in Mobile | Classic
Share by: