تحسين سلوك النقر في WKWebView

اختيار النظام الأساسي: Android جديد Android iOS

إذا كان تطبيقك يستخدم WKWebView لعرض محتوى الويب، قد يكون من المفيد تحسين سلوك النقر للأسباب التالية:

  • لا يتيح WKWebView تصفُّح الويب بعلامات التبويب. لا تؤدي النقرات على الإعلانات التي تحاول فتح علامة تبويب جديدة أي إجراء تلقائيًا.

  • تؤدي النقرات على الإعلانات التي تفتح في علامة التبويب نفسها إلى إعادة تحميل الصفحة. قد يكون من المفيد فرض فتح النقرات على الإعلانات خارج WKWebView، مثلاً إذا كنت تستضيف ألعاب H5 وأردت الحفاظ على حالة كل لعبة.

  • لا تتيح ميزة "الملء التلقائي" استخدام معلومات بطاقة الائتمان في WKWebView. قد يؤدي ذلك إلى انخفاض عدد الإحالات الناجحة للتجارة الإلكترونية لدى المعلنين، ما يؤثر سلبًا في تحقيق الربح من محتوى الويب.

يقدّم هذا الدليل خطوات مقترَحة لتحسين سلوك النقر في عروض الويب على الأجهزة الجوّالة مع الحفاظ على محتوى عرض الويب.

المتطلبات الأساسية

التنفيذ

يمكن أن تتضمّن روابط الإعلانات سمة href التي يمكن ضبطها على _blank أو _top أو _self أو _parent. باستخدام "إدارة الإعلانات"، يمكنك التحكّم في السمة المستهدَفة لضبطها على _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. اضبط WKUIDelegate على مثيل WKWebView.

  2. اضبط WKNavigationDelegate على مثيل WKWebView.

  3. حدِّد ما إذا كنت تريد تحسين سلوك عنوان URL للنقر.

    • تحقَّق مما إذا كانت السمة navigationType في عنصر WKNavigationAction هي نوع النقر الذي تريد تحسينه. يتحقّق مثال الرمز من .linkActivated الذي لا ينطبق إلا على النقرات على رابط يتضمّن سمة href.

    • تحقَّق من السمة targetFrame في عنصر WKNavigationAction. إذا كانت تعرض nil، يعني ذلك أنّ هدف التنقّل هو نافذة جديدة. بما أنّ WKWebView لا يمكنه التعامل مع هذا النقر، يجب التعامل مع هذه النقرات يدويًا.

  4. حدِّد ما إذا كنت تريد فتح عنوان URL في متصفّح خارجي أو SFSafariViewController أو عرض الويب الحالي. توضّح قصاصة الرمز كيفية فتح عناوين URL التي تنتقل خارج الموقع الإلكتروني من خلال عرض 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? {
    // 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;
}

اختبار التنقّل في الصفحة

لاختبار التغييرات التي أجريتها على التنقّل في الصفحة، حمِّل

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

في عرض الويب. انقر على كل نوع من أنواع الروابط المختلفة لمعرفة سلوكها في تطبيقك.

وفي ما يلي بعض النقاط التي يجب التحقق منها:

  • يفتح كل رابط عنوان URL المقصود.
  • عند العودة إلى التطبيق، لا تتم إعادة ضبط عدّاد صفحة الاختبار إلى الصفر للتحقّق من الحفاظ على حالة الصفحة.