إتاحة نوافذ متعددة وأجهزة قابلة للطي

يمكن للتطبيقات التي تتيح استخدام نوافذ متعددة على أجهزة iPad أو التي تعمل على الأجهزة القابلة للطي، مثل iPhone Duo، عرض واجهة المستخدم بأحجام نوافذ وإعدادات شاشة ديناميكية. على أجهزة iPad، يمكن للمستخدمين التفاعل مع نُسخ متزامنة متعددة من واجهة مستخدم التطبيق وتغيير حجم النوافذ. على الأجهزة القابلة للطي، تحدّد حالة طي الجهاز الشاشة النشطة. وعند فتحه، يستخدم الجهاز الشاشة الداخلية الأكبر حجمًا. عند طي الجهاز، يتم استخدام الشاشة الخارجية الأصغر حجمًا

يتناول هذا الدليل تحميل الإعلانات وعرضها في بيئات النوافذ المتعدّدة والشاشات القابلة للطي.

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

قبل البدء، أكمِل ما يلي:

ضبط مشهد النافذة في طلب عرض الإعلان

لتلقّي إعلان يناسب نافذة معيّنة أو شاشة نشطة، يمكنك تخصيص عنصر UIWindowScene النشط للسمة scene في عنصر GADRequest. يعرض Google Mobile Ads SDK إعلانًا بحجم مناسب لذلك المشهد. في SwiftUI، يمكنك الاستعلام عن المشاهد المتصلة للحصول على مشهد نافذة المقدمة النشطة.

يضبط المثال التالي مشهد النافذة، ويحمّل إعلانًا بينيًا في حال النجاح، ويسجّل رسالة خطأ في حال الفشل:

Swift

func loadInterstitial() async {
  let request = Request()
  request.scene = view.window?.windowScene

  do {
    interstitial = try await InterstitialAd.load(
      with: "ca-app-pub-3940256099942544/4411468910", request: request)
  } catch {
    print("Failed to load interstitial ad with error: \(error.localizedDescription)")
  }
}

SwiftUI

func loadInterstitial() async {
  let request = Request()
  request.scene =
    UIApplication.shared.connectedScenes
    .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene

  do {
    let _ = try await InterstitialAd.load(
      with: "ca-app-pub-3940256099942544/4411468910", request: request)
  } catch {
    print("Failed to load interstitial ad with error: \(error.localizedDescription)")
  }
}

Objective-C

- (void)loadInterstitial {
  GADRequest *request = [GADRequest request];
  request.scene = self.view.window.windowScene;

  [GADInterstitialAd
       loadWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910"
                request:request
      completionHandler:^(GADInterstitialAd *ad, NSError *error) {
        if (error) {
          NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]);
          return;
        }
        self.interstitial = ad;
      }];
}

في وضع الاختبار، يتعذّر إرسال طلبات عرض الإعلانات مع ظهور الخطأ التالي إذا كان تطبيقك المتعدّد المشاهد يطلب إعلانًا بدون تمرير مشهد:

<Google> Invalid Request. The GADRequest scene property should be set for
applications that support multi-scene. Treating the unset property as an error
while in test mode.

في وضع الإنتاج، يتم ملء طلب عرض الإعلان، ولكن يتعذّر عرض الإعلان إذا تم عرضه في نافذة أصغر من حجم محتوى الإعلان:

<Google> Ad cannot be presented. The full screen ad content size exceeds the current window size.

إنشاء طلب عرض الإعلان

عند إرسال طلبات عرض الإعلانات، تتطلّب التطبيقات المتعدّدة المشاهد مشهد نافذة صالحًا. عند تعبئة مشهد النافذة، أنشئ طلبات عرض الإعلانات باستخدام الطريقة viewDidAppear. ننصح بهذه العملية لأنّه لم تتم إضافة طريقة عرض إلى نافذة في طريقة viewDidLoad بعد.

على الرغم من أنّه يمكنك استدعاء طريقة viewDidAppear أكثر من مرة في مراحل نشاط التطبيق، يجب تضمين طلب عرض الإعلان في علامة منطقية ليتم تشغيله مرة واحدة فقط.

يعمل المثال التالي على إعداد طلب عرض الإعلان في طريقة viewDidAppear:

Swift

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  if !requestInitialized {
    Task {
      await loadInterstitial()
    }
    requestInitialized = true
  }
}

Objective-C

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  if (!_requestInitialized) {
    [self loadInterstitial];
    _requestInitialized = YES;
  }
}

التعامل مع تغيير حجم النافذة

تتغير أبعاد النافذة عندما يغير المستخدمون حجم المشاهد على iPad أو يطوون ويفتحون جهازًا قابلاً للطي مثل iPhone Duo. عندما يتغيّر حجم النافذة، تأكّد من أنّ الإعلانات التي تم تحميلها تناسب الأبعاد المعدَّلة وأعِد تحميل الإعلانات إذا لزم الأمر.

للتأكّد من أنّ الإعلانات المحمَّلة تناسب الأبعاد المعدَّلة، استخدِم إحدى الطريقتَين التاليتَين:

الإعلانات بملء الشاشة

للتحقّق مما إذا كان الإعلان بملء الشاشة الذي تم تحميله لا يزال صالحًا لحجم النافذة أو حالة الطي المعدَّلَين، استخدِم طريقة canPresentFromRootViewController:error:. وإذا تعذّر التحقّق، يتم تحميل إعلان بحجم المشهد المعدَّل.

يتحقّق المثال التالي مما إذا كان يمكن عرض "إعلان بيني" بعد تغيير الحجم، ويعيد تحميل الإعلان إذا لزم الأمر:

Swift

override func viewWillTransition(
  to size: CGSize,
  with coordinator: UIViewControllerTransitionCoordinator
) {
  super.viewWillTransition(to: size, with: coordinator)

  coordinator.animate(alongsideTransition: nil) { [weak self] _ in
    guard let self else { return }
    do {
      try self.interstitial?.canPresent(from: self)
    } catch {
      Task {
        await self.loadInterstitial()
      }
    }
  }
}

Objective-C

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

  [coordinator
      animateAlongsideTransition:nil
                      completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
                        if (![self.interstitial canPresentFromRootViewController:self error:nil]) {
                          [self loadInterstitial];
                        }
                      }];
}

تعامَل مع تغيير حجم النافذة وعمليات الانتقال عند الطي بشكل مشابه لتدوير الجهاز. يمكنك حصر مشاهدات البانر على الموقع الإلكتروني safeAreaLayoutGuide. تتيح هذه العملية بقاء الإعلانات بعيدة عن مفصلات الأجهزة والفتحات وأشرطة النظام. تعيد هذه العملية أيضًا احتساب حجم "إعلان البانر التكيُّفي الثابت" باستخدام عرض المنطقة الآمنة المعدَّل.

يحمّل المثال التالي &quot;إعلان بانر تكيُّفي ثابت&quot; بعرض النافذة المعدَّل أثناء تغيير الحجم:

Swift

override func viewWillTransition(
  to size: CGSize,
  with coordinator: UIViewControllerTransitionCoordinator
) {
  super.viewWillTransition(to: size, with: coordinator)

  coordinator.animate(alongsideTransition: nil) { [weak self] _ in
    self?.loadBannerAd()
  }
}

@MainActor
func loadBannerAd() {
  let frame = view.frame.inset(by: view.safeAreaInsets)
  let viewWidth = frame.size.width

  bannerView.adSize = largeAnchoredAdaptiveBanner(width: viewWidth)

  let request = Request()
  request.scene = view.window?.windowScene
  bannerView.load(request)
}

SwiftUI

struct MultiSceneBannerView: View {
  var body: some View {
    GeometryReader { geometry in
      let adSize = largeAnchoredAdaptiveBanner(width: geometry.size.width)
      MultiSceneBannerViewContainer(adSize: adSize)
        .frame(width: adSize.size.width, height: adSize.size.height)
    }
  }
}

private struct MultiSceneBannerViewContainer: UIViewRepresentable {
  let adSize: AdSize

  func makeUIView(context: Context) -> BannerView {
    let bannerView = BannerView(adSize: adSize)
    let request = Request()
    request.scene =
      UIApplication.shared.connectedScenes
      .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
    bannerView.load(request)
    return bannerView
  }

  func updateUIView(_ uiView: BannerView, context: Context) {
    if uiView.adSize.size != adSize.size {
      uiView.adSize = adSize
      let request = Request()
      request.scene = uiView.window?.windowScene
      uiView.load(request)
    }
  }
}

Objective-C

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

  [coordinator
      animateAlongsideTransition:nil
                      completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
                        [self loadBannerAd];
                      }];
}

- (void)loadBannerAd {
  dispatch_async(dispatch_get_main_queue(), ^{
    CGRect frame = UIEdgeInsetsInsetRect(self.view.frame, self.view.safeAreaInsets);
    CGFloat viewWidth = frame.size.width;

    self.bannerView.adSize = GADLargeAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth);

    GADRequest *request = [GADRequest request];
    request.scene = self.view.window.windowScene;
    [self.bannerView loadRequest:request];
  });
}

إعلانات مدمجة مع المحتوى

يمكنك التحكّم في تنسيق "الإعلانات المدمجة مع المحتوى". وعلى عكس إعلانات البانر أو الإعلانات بملء الشاشة، لا تحتاج إلى إعادة تحميل "الإعلانات المدمجة مع المحتوى" عند تغيير حجم النافذة. استخدِم قيود التنسيق التلقائي العادية أو تنسيقات SwiftUI لكي يتكيّف عرض الإعلان المدمج مع المحتوى مع التغييرات في الحجم.