If your iOS 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.
- Google Sign-in
isn't
supported in
WKWebView
.
This guide provides recommended steps to optimize the click behavior in mobile web views while preserving the web view content.
Prerequisites
- Complete the Set up the web view guide.
Implementation
Ad links can have the href
target attribute set to either _blank
, _top
,
_self
, or _parent
.
With Ad Manager you can control the target attribute to be _blank
or _top
by setting ads to open in a new tab or
window.
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:
Set the
WKUIDelegate
on yourWKWebView
instance.Set the
WKNavigationDelegate
on yourWKWebView
instance.- Implement
webView(_:decidePolicyFor:decisionHandler:)
.
- Implement
Determine whether to optimize the behavior of the click URL.
Check if the
navigationType
property on theWKNavigationAction
object is a click type you want to optimize. The code snippet checks for.linkActivated
which only applies to clicks on a link with anhref
attribute.Check the
targetFrame
property on theWKNavigationAction
object. If it returnsnil
, it means the target of the navigation is a new window. SinceWKWebView
can't handle that click, these clicks must be handled manually.
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 aSFSafariViewController
.
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? {
guard let url = navigationAction.request.url,
let currentDomain = webView.url?.host,
let targetDomain = url.host else { return nil }
// 3. Determine whether to optimize the behavior of the click URL.
if didHandleClickBehavior(
url: url,
currentDomain: currentDomain,
targetDomain: targetDomain,
navigationAction: navigationAction) {
print("URL opened in SFSafariViewController.")
}
return nil
}
// Implement the WKNavigationDelegate method.
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
{
guard let url = navigationAction.request.url,
let currentDomain = webView.url?.host,
let targetDomain = url.host else { return decisionHandler(.cancel) }
// 3. Determine whether to optimize the behavior of the click URL.
if didHandleClickBehavior(
url: url,
currentDomain: currentDomain,
targetDomain: targetDomain,
navigationAction: navigationAction) {
return decisionHandler(.cancel)
}
decisionHandler(.allow)
}
// Implement a helper method to handle click behavior.
func didHandleClickBehavior(
url: URL,
currentDomain: String,
targetDomain: String,
navigationAction: WKNavigationAction) -> Bool {
// Check if the navigationType is a link with an href attribute or
// if the target of the navigation is a new window.
guard 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 else { return false }
// 4. Open the URL in a SFSafariViewController.
let safariViewController = SFSafariViewController(url: url)
present(safariViewController, animated: true)
return true
}
}
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 {
NSURL *url = navigationAction.request.URL;
NSString *currentDomain = webView.URL.host;
NSString *targetDomain = navigationAction.request.URL.host;
// 3. Determine whether to optimize the behavior of the click URL.
if ([self didHandleClickBehaviorForURL: url
currentDomain: currentDomain
targetDomain: targetDomain
navigationAction: navigationAction]) {
NSLog(@"URL opened in SFSafariViewController.");
}
return nil;
}
// Implement the WKNavigationDelegate method.
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:
(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
NSString *currentDomain = webView.URL.host;
NSString *targetDomain = navigationAction.request.URL.host;
// 3. Determine whether to optimize the behavior of the click URL.
if ([self didHandleClickBehaviorForURL: url
currentDomain: currentDomain
targetDomain: targetDomain
navigationAction: navigationAction]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
// Implement a helper method to handle click behavior.
- (BOOL)didHandleClickBehaviorForURL:(NSURL *)url
currentDomain:(NSString *)currentDomain
targetDomain:(NSString *)targetDomain
navigationAction:(WKNavigationAction *)navigationAction {
if (!url || !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:url];
[self presentViewController:safariViewController animated:YES
completion:nil];
return YES;
}
return NO;
}
Test your page navigation
To test your page navigation changes, load
https://webview-api-for-ads-test.glitch.me#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.