顯示系統定義的原生廣告格式
原生廣告載入後,您的應用程式會透過 GADAdLoaderDelegate 通訊協定訊息,收到一個原生廣告物件,接著負責顯示廣告 (不一定要立即顯示)。為方便呈現系統定義的廣告格式,SDK 提供了一些實用資源。
GADNativeAdView
GADNativeAd 對應的「廣告檢視區塊」類別是 GADNativeAdView。這個廣告檢視區塊類別是一個 UIView,供發布商用來呈現廣告。例如,一個 GADNativeAdView 可以顯示單一的 GADNativeAd 例項。所有用來呈現廣告素材資源的 UIView 物件,都應做為這個 GADNativeAdView 物件的子檢視區塊。
舉例來說,如要在 UITableView 中顯示廣告,其中一個儲存格的檢視區塊階層可能如下所示:

GADNativeAdView 類別也提供 IBOutlets,用於註冊每個素材資源所用的檢視區塊,以及註冊 GADNativeAd 物件本身的方法。透過這種方式註冊檢視區塊後,SDK 就能自動處理以下工作:
- 記錄點擊。
- 記錄曝光 (當廣告的第一個像素出現在螢幕上時)。
- 顯示 AdChoices 廣告標籤。
AdChoices 廣告標籤
對於間接原生廣告 (透過 Ad Manager 候補廣告、Ad Exchange 或 AdSense 放送),SDK 會自動加入 AdChoices 廣告標籤。請在原生廣告檢視區塊中,預留一個您偏好的角落,供系統自動插入 AdChoices 標誌,並確保圖示在該位置清晰可見。如要進一步瞭解這個廣告標籤的外觀與功能,請參閱程式輔助原生廣告導入指南。
程式輔助原生廣告的廣告標示
顯示程式輔助原生廣告時,必須加上廣告標示,表明該檢視區塊為廣告內容,詳情請參閱政策規範。程式碼範例
本節說明如何用從 xib 檔案動態載入的檢視區塊,來顯示原生廣告。當 GADAdLoaders 設為請求多種格式時,這種做法非常實用。
設計 UIView 布局
第一步是擺放用來呈現原生廣告素材資源的 UIViews。您可以像建立其他 xib 檔案一樣,在 Interface Builder 中完成這項設定。以下是一個原生廣告版面配置範例:

請注意圖片右上方的「Custom Class」值已設為
GADNativeAdView,這個類別就是用來呈現 GADNativeAd 的廣告檢視區塊。
您也需要設定 GADMediaView 的自訂類別,用於呈現廣告的影片或圖片。
將 outlet 連結至檢視區塊
當檢視區塊就位,版面配置也已指定正確的廣告檢視區塊類別後,請將廣告檢視區塊的素材資源 outlet,連結至已建立的 UIViews。以下示範如何將廣告檢視區塊的素材資源 outlet,連結至建立給廣告的 UIViews:

在 outlet 面板中,GADNativeAdView 中的 outlet 已連結至 Interface Builder 中擺放的 UIViews。這樣 SDK 就能知道每個 UIView 會顯示的素材資源。另請注意,這些 outlet 代表廣告中可點擊的檢視區塊。
顯示廣告
完成版面配置並連結 outlet 後,請在應用程式中加入下列程式碼,讓廣告載入後能立即顯示:
Swift
func adLoader(_ adLoader: AdLoader, didReceive nativeAd: NativeAd) {
  // ...
  // Set ourselves as the native ad delegate to be notified of native ad events.
  nativeAd.delegate = self
  // Populate the native ad view with the native ad assets.
  // The headline and mediaContent are guaranteed to be present in every native ad.
  (nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
  nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
  // Some native ads will include a video asset, while others do not. Apps can use the
  // GADVideoController's hasVideoContent property to determine if one is present, and adjust their
  // UI accordingly.
  let mediaContent = nativeAd.mediaContent
  if mediaContent.hasVideoContent {
    // By acting as the delegate to the GADVideoController, this ViewController receives messages
    // about events in the video lifecycle.
    mediaContent.videoController.delegate = self
    videoStatusLabel.text = "Ad contains a video asset."
  } else {
    videoStatusLabel.text = "Ad does not contain a video."
  }
  // This app uses a fixed width for the GADMediaView and changes its height to match the aspect
  // ratio of the media it displays.
  if let mediaView = nativeAdView.mediaView, nativeAd.mediaContent.aspectRatio > 0 {
    let aspectRatioConstraint = NSLayoutConstraint(
      item: mediaView,
      attribute: .width,
      relatedBy: .equal,
      toItem: mediaView,
      attribute: .height,
      multiplier: CGFloat(nativeAd.mediaContent.aspectRatio),
      constant: 0)
    mediaView.addConstraint(aspectRatioConstraint)
    nativeAdView.layoutIfNeeded()
  }
  // These assets are not guaranteed to be present. Check that they are before
  // showing or hiding them.
  (nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
  nativeAdView.bodyView?.isHidden = nativeAd.body == nil
  (nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
  nativeAdView.callToActionView?.isHidden = nativeAd.callToAction == nil
  (nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
  nativeAdView.iconView?.isHidden = nativeAd.icon == nil
  (nativeAdView.starRatingView as? UIImageView)?.image = imageOfStars(from: nativeAd.starRating)
  nativeAdView.starRatingView?.isHidden = nativeAd.starRating == nil
  (nativeAdView.storeView as? UILabel)?.text = nativeAd.store
  nativeAdView.storeView?.isHidden = nativeAd.store == nil
  (nativeAdView.priceView as? UILabel)?.text = nativeAd.price
  nativeAdView.priceView?.isHidden = nativeAd.price == nil
  (nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
  nativeAdView.advertiserView?.isHidden = nativeAd.advertiser == nil
  // In order for the SDK to process touch events properly, user interaction should be disabled.
  nativeAdView.callToActionView?.isUserInteractionEnabled = false
  // Associate the native ad view with the native ad object. This is
  // required to make the ad clickable.
  // Note: this should always be done after populating the ad views.
  nativeAdView.nativeAd = nativeAd
}
SwiftUI
建立檢視區塊模型
您可以建立檢視區塊模型,用於載入原生廣告及發布廣告資料異動:
import GoogleMobileAds
class NativeAdViewModel: NSObject, ObservableObject, NativeAdLoaderDelegate {
  @Published var nativeAd: NativeAd?
  private var adLoader: AdLoader!
  func refreshAd() {
    adLoader = AdLoader(
      adUnitID: "ca-app-pub-3940256099942544/3986624511",
      // The UIViewController parameter is optional.
      rootViewController: nil,
      adTypes: [.native], options: nil)
    adLoader.delegate = self
    adLoader.load(Request())
  }
  func adLoader(_ adLoader: AdLoader, didReceive nativeAd: NativeAd) {
    // Native ad data changes are published to its subscribers.
    self.nativeAd = nativeAd
    nativeAd.delegate = self
  }
  func adLoader(_ adLoader: AdLoader, didFailToReceiveAdWithError error: Error) {
    print("\(adLoader) failed with error: \(error.localizedDescription)")
  }
}
建立 UIViewRepresentable
建立 NativeView 的 UIViewRepresentable,並監控 ViewModel 類別中資料的異動。
private struct NativeAdViewContainer: UIViewRepresentable {
  typealias UIViewType = NativeAdView
  // Observer to update the UIView when the native ad value changes.
  @ObservedObject var nativeViewModel: NativeAdViewModel
  func makeUIView(context: Context) -> NativeAdView {
    return
      Bundle.main.loadNibNamed(
        "NativeAdView",
        owner: nil,
        options: nil)?.first as! NativeAdView
  }
  func updateUIView(_ nativeAdView: NativeAdView, context: Context) {
    guard let nativeAd = nativeViewModel.nativeAd else { return }
    // Each UI property is configurable using your native ad.
    (nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
    nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
    (nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
    (nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
    (nativeAdView.starRatingView as? UIImageView)?.image = imageOfStars(from: nativeAd.starRating)
    (nativeAdView.storeView as? UILabel)?.text = nativeAd.store
    (nativeAdView.priceView as? UILabel)?.text = nativeAd.price
    (nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
    (nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
    // For the SDK to process touch events properly, user interaction should be disabled.
    nativeAdView.callToActionView?.isUserInteractionEnabled = false
    // Associate the native ad view with the native ad object. This is required to make the ad
    // clickable.
    // Note: this should always be done after populating the ad views.
    nativeAdView.nativeAd = nativeAd
  }
將檢視區塊新增至檢視區塊階層
以下示範如何將 UIViewRepresentable 新增至檢視區塊階層:
struct NativeContentView: View {
  // Single source of truth for the native ad data.
  @StateObject private var nativeViewModel = NativeAdViewModel()
  var body: some View {
    ScrollView {
      VStack(spacing: 20) {
        // Updates when the native ad data changes.
        NativeAdViewContainer(nativeViewModel: nativeViewModel)
          .frame(minHeight: 300)  // minHeight determined from xib.
Objective-C
- (void)adLoader:(GADAdLoader *)adLoader didReceiveNativeAd:(GADNativeAd *)nativeAd {
  // ...
  GADNativeAdView *nativeAdView = self.nativeAdView;
  // Set ourselves as the ad delegate to be notified of native ad events.
  nativeAd.delegate = self;
  // Populate the native ad view with the native ad assets.
  // The headline and mediaContent are guaranteed to be present in every native ad.
  ((UILabel *)nativeAdView.headlineView).text = nativeAd.headline;
  nativeAdView.mediaView.mediaContent = nativeAd.mediaContent;
  // This app uses a fixed width for the GADMediaView and changes its height
  // to match the aspect ratio of the media content it displays.
  if (nativeAdView.mediaView != nil && nativeAd.mediaContent.aspectRatio > 0) {
    NSLayoutConstraint *aspectRatioConstraint =
        [NSLayoutConstraint constraintWithItem:nativeAdView.mediaView
                                     attribute:NSLayoutAttributeWidth
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:nativeAdView.mediaView
                                     attribute:NSLayoutAttributeHeight
                                    multiplier:(nativeAd.mediaContent.aspectRatio)
                                      constant:0];
    [nativeAdView.mediaView addConstraint:aspectRatioConstraint];
    [nativeAdView layoutIfNeeded];
  }
  if (nativeAd.mediaContent.hasVideoContent) {
    // By acting as the delegate to the GADVideoController, this ViewController
    // receives messages about events in the video lifecycle.
    nativeAd.mediaContent.videoController.delegate = self;
    self.videoStatusLabel.text = @"Ad contains a video asset.";
  } else {
    self.videoStatusLabel.text = @"Ad does not contain a video.";
  }
  // These assets are not guaranteed to be present. Check that they are before
  // showing or hiding them.
  ((UILabel *)nativeAdView.bodyView).text = nativeAd.body;
  nativeAdView.bodyView.hidden = nativeAd.body ? NO : YES;
  [((UIButton *)nativeAdView.callToActionView) setTitle:nativeAd.callToAction
                                               forState:UIControlStateNormal];
  nativeAdView.callToActionView.hidden = nativeAd.callToAction ? NO : YES;
  ((UIImageView *)nativeAdView.iconView).image = nativeAd.icon.image;
  nativeAdView.iconView.hidden = nativeAd.icon ? NO : YES;
  ((UIImageView *)nativeAdView.starRatingView).image = [self imageForStars:nativeAd.starRating];
  nativeAdView.starRatingView.hidden = nativeAd.starRating ? NO : YES;
  ((UILabel *)nativeAdView.storeView).text = nativeAd.store;
  nativeAdView.storeView.hidden = nativeAd.store ? NO : YES;
  ((UILabel *)nativeAdView.priceView).text = nativeAd.price;
  nativeAdView.priceView.hidden = nativeAd.price ? NO : YES;
  ((UILabel *)nativeAdView.advertiserView).text = nativeAd.advertiser;
  nativeAdView.advertiserView.hidden = nativeAd.advertiser ? NO : YES;
  // In order for the SDK to process touch events properly, user interaction
  // should be disabled.
  nativeAdView.callToActionView.userInteractionEnabled = NO;
  // Associate the native ad view with the native ad object. This is
  // required to make the ad clickable.
  // Note: this should always be done after populating the ad views.
  nativeAdView.nativeAd = nativeAd;
}
GitHub 完整範例程式碼
點選下方的 GitHub 連結,即可查看使用 Swift、SwiftUI 和 Objective-C 整合原生廣告的完整範例。
Swift 自訂顯示範例 SwiftUI 原生廣告範例 Objective-C 自訂顯示範例
GADMediaView
圖片和影片素材資源會透過 GADMediaView 向使用者顯示。這個 UIView 可以在 xib 檔案中定義,也可以動態建構,而且和其他素材資源檢視區塊一樣,應加入 GADNativeAdView 的檢視區塊階層。
和其他素材資源檢視區塊一樣,媒體檢視區塊需要填入內容才能正常顯示。您可以透過 GADMediaView 的 mediaContent 屬性設定內容,而 GADNativeAd 的 mediaContent 屬性則提供可傳遞至 GADMediaView 的媒體內容。
以下是自訂顯示範例 (Swift
| Objective-C) 的程式碼片段,示範如何將 GADNativeAd 的 GADMediaContent 填入 GADMediaView,呈現原生廣告素材資源:
Swift
nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
Objective-C
nativeAdView.mediaView.mediaContent = nativeAd.mediaContent;
請確認在原生廣告檢視區塊的 Interface Builder 檔案中,您已將檢視區塊的自訂類別設為 GADMediaView,並連結至 mediaView outlet。
變更圖片內容模式
GADMediaView 類別在顯示圖片時,會遵循 UIView 的 contentMode 屬性設定。如想調整圖片在 GADMediaView 中的縮放方式,請在 GADMediaView 的 contentMode 屬性上設定對應的 UIViewContentMode。
例如,當廣告沒有影片時,顯示圖片並填滿 GADMediaView:
Swift
nativeAdView.mediaView?.contentMode = .scaleAspectFit
Objective-C
GADMediaView *mediaView = nativeAdView.mediaView;
if (mediaView) {
  mediaView.contentMode = UIViewContentModeScaleAspectFit;
}
GADMediaContent
GADMediaContent 類別會保存與原生廣告媒體內容相關的資料,而這些資料會透過 GADMediaView 類別顯示。當這個類別設定至 GADMediaView 的 mediaContent 屬性時:
- 如果廣告包含影片素材資源,影片會先緩衝處理,然後在 - GADMediaView中播放。您可以檢查- hasVideoContent來確定是否有影片素材資源。
- 如果廣告不含影片素材資源,系統會下載 - mainImage素材資源並顯示在- GADMediaView中。
後續步驟
進一步瞭解使用者隱私。