优化 WKWebView 点击行为

如果您的 iOS 应用使用了 WKWebView 来展示 Web 内容,您可能希望 出于以下原因考虑优化点击行为:

  • WKWebView 不 支持 标签页式浏览。试图打开新标签页的广告点击 默认值。

  • 系统会重新加载在同一标签页中打开的广告点击页面。您可能希望 广告点击在 WKWebView 之外打开,例如:如果您托管了 H5 游戏 来维护每个游戏的状态

  • 自动填充功能不支持WKWebView中的信用卡信息。这可能会造成 会导致广告客户的电子商务转化次数减少,对 网络内容的创收

本指南介绍了针对移动设备优化点击行为的推荐步骤 同时保留网页视图内容。

前提条件

实现

广告链接的 href 目标属性可设置为 _blank_top_self_parent。 借助 Ad Manager,您可以将目标属性控制为 _blank_top 将广告设为在新标签页中打开或 窗口。 广告链接还可以包含 JavaScript 函数,例如 window.open(url, "_blank")

下表介绍了这些链接在网页视图中的行为。

href 个目标属性 默认的 WKWebView 点击行为
target="_blank" 网页数据视图不会处理链接。
target="_top" 在现有网页视图中重新加载链接。
target="_self" 在现有网页视图中重新加载链接。
target="_parent" 在现有网页视图中重新加载链接。
JavaScript 函数 默认的 WKWebView 点击行为
window.open(url, "_blank") 网页数据视图不会处理链接。

请按照以下步骤优化 WKWebView 实例:

  1. WKWebView 上设置 WKUIDelegate 实例。

  2. 设置WKNavigationDelegate WKWebView 实例。

  3. 确定是否优化点击跟踪网址的行为。

    • 检查 navigationType 属性是否处于开启状态 WKNavigationAction 对象是 要优化的点击类型代码段会检查 (.linkActivated) 这仅适用于对具有 href 属性的链接获得的点击。

    • 查看targetFrame 属性。WKNavigationAction如果它返回 nil,则表示 导航目标是新窗口。由于WKWebView无法处理 必须手动处理这些点击。

  4. 决定是否在外部浏览器中打开网址、 SFSafariViewController、 还是现有的网页视图此代码段展示了如何打开离开网页的网址 显示 SFSafariViewController

代码示例

以下代码段展示了如何优化网页视图的点击行为。如 例如,它会检查当前网域是否与目标网域不同。 这只是一种方法,因为您使用的标准可能会有所不同。

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;
}

测试网页导航

要测试页面导航更改,请加载

https://webview-api-for-ads-test.glitch.me#click-behavior-tests

进入网页视图点击各种不同的链接类型,查看它们是如何 行为

请检查以下几个方面:

  • 每个链接都会打开目标网址。
  • 返回应用时,测试页的计数器不会重置为零, 验证是否保留了网页状态。