在 iOS 应用中添加原生广告

原生广告 API 可帮助您为应用中展示的广告打造自定义体验。使用原生广告 API 时,您会收到一组广告属性(例如标题、图片、行动号召),而不是可以直接展示的广告,您需要使用这些广告属性来构建用于展示广告的自定义 UIView。

请参阅原生广告指南,了解如何在您的应用中设计原生广告。

让我们实现以下原生广告版位。您要在原生广告中创建以下视图。

视图 1:广告主图标

视图 2:广告标题

视图 3:赞助状态标签

视图 4:广告主选择

视图 5:广告素材视图

视图 6:社交关系

视图 7:广告正文

视图 8:广告行动号召按钮


第 1 步:在 Storyboard 中创建原生广告视图

第 2 步:加载并展示原生广告

第 3 步:如何获取内容的宽高比与应用自然的宽度和高度

第 4 步:验证展示次数和点击量记录

第 5 步:广告无法显示时如何调试

第 6 步:在不自动缓存的情况下加载广告

第 7 步:测试广告集成

查看更新日志中的已知问题

第 1 步:在 Storyboard 中创建原生广告视图

请确保先阅读 Audience Network 入门指南iOS 入门指南,然后再继续操作。

设计原生广告和横幅广告时,请务必遵守 iOS 布局指南,以便打造最佳的用户体验。

  1. 按照 iOS 入门指南的说明创建新项目后,打开 Main.storyboard。将 UIView 元素添加到主要 View 元素,并命名为 adUIView


  2. 此外,如下图所示,在 adUIView 下添加 adIconImageView (FBMediaView)、adTitleLabel (UILabel)、adCoverMediaView (FBMediaView)、adSocialContext (UILabel), adCallToActionButton (UIButton)、adOptionsView (FBAdOptionsView)、adBodyLabel (UILabel)、sponsoredLabel (UILabel)。


  3. 您可能会注意到,视图控制器场景附近有一个红色箭头。这通常表示布局中缺少限制。


    您可能需要选择场景中的所有视图对象,然后点击“解决布局问题”图标,以便添加缺少的限制。


  4. 现在,您已创建用于展示原生广告的所有用户界面元素,接下来需要在 ViewController 界面中引用这些用户界面元素。首先打开 ViewController.m(如果您使用的是 Swift,则打开 ViewController.swift),然后将 adUIView 拖动到 ViewController 对象内。您可以将其命名为 adUIView。然后对 adIconImageViewadTitleLabeladCoverMediaViewadSocialContextadCallToActionButtonadOptionsViewadBodyLabelsponsoredLabel 执行相同操作。


  5. 构建并运行项目。您应该会在设备或模拟器上看到如下所示的空内容:

现在,您已创建用于展示原生广告的所有用户界面元素,下一步是加载原生广告并将内容绑定到用户界面元素。

第 2 步:加载并展示原生广告

  1. 在视图控制器源文件中,导入 SDK、声明 ViewController 符合 FBNativeAdDelegate 协议,然后添加 FBNativeAd 实例变量
    import UIKit
    import FBAudienceNetwork
    
    class ViewController: UIViewController, FBNativeAdDelegate {
        
      private var nativeAd: FBNativeAd?
    }
    #import <UIKit/UIKit.h>
    @import FBAudienceNetwork;
    
    @interface ViewController () <FBNativeAdDelegate>
    
    @property (strong, nonatomic) FBNativeAd *nativeAd;
    
    @end

  2. viewDidLoad 方法中,添加以下几行代码,用于加载原生广告内容
    override func viewDidLoad() {
      super.viewDidLoad()
        
      let nativeAd = FBNativeAd(placementID: "YOUR_PLACEMENT_ID")
      nativeAd.delegate = self
      nativeAd.loadAd()
    }
    - (void)viewDidLoad 
    {
      [super viewDidLoad];
    
      FBNativeAd *nativeAd = [[FBNativeAd alloc] initWithPlacementID:@"YOUR_PLACEMENT_ID"];
      nativeAd.delegate = self;
      [nativeAd loadAd];
    }

    YOUR_PLACEMENT_ID 中显示的编号为临时编号,仅供测试使用。

    若您在实时代码中使用此临时编号,您的用户便不会收到广告(他们会收到未填充错误)。您必须在测试之后返回此处,将临时编号换成实时版位编号。

    若想了解如何生成实时版位编号,请参阅 Audience Network 设置

  3. 在内容准备就绪后,下一步是展示广告。您可能需要 ViewController 来实现 nativeAdDidLoad 委托方法
    func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
        
      // 1. If there is an existing valid native ad, unregister the view
      if let previousNativeAd = self.nativeAd, previousNativeAd.isAdValid {
        previousNativeAd.unregisterView()
      }
        
      // 2. Retain a reference to the native ad object
      self.nativeAd = nativeAd
    
      // 3. Register what views will be tappable and what the delegate is to notify when a registered view is tapped
      // Here only the call-to-action button and the media view are tappable, and the delegate is the view controller
      nativeAd.registerView(
        forInteraction: adUIView,
        mediaView: adCoverMediaView,
        iconView: adIconImageView,
        viewController: self,
        clickableViews: [adCallToActionButton, adCoverMediaView]
      )
        
      // 4. Render the ad content onto the view
      adTitleLabel.text = nativeAd.advertiserName
      adBodyLabel.text = nativeAd.bodyText
      adSocialContextLabel.text = nativeAd.socialContext
      sponsoredLabel.text = nativeAd.sponsoredTranslation
      adCallToActionButton.setTitle(nativeAd.callToAction, for: .normal)
      adOptionsView.nativeAd = nativeAd
    }
    - (void)nativeAdDidLoad:(FBNativeAd *)nativeAd
    {
      // 1. If there is an existing valid native ad, unregister the view
      if (self.nativeAd && self.nativeAd.isAdValid) {
        [self.nativeAd unregisterView];
      }
    
      // 2. Retain a reference to the native ad object
      self.nativeAd = nativeAd;
    
      // 3. Register what views will be tappable and what the delegate is to notify when a registered view is tapped
      // Here only the call-to-action button and the media view are tappable, and the delegate is the view controller
      [self.nativeAd registerViewForInteraction:self.adUIView
                                      mediaView:self.adCoverMediaView
                                       iconView:self.adIconImageView
                                 viewController:self
                                 clickableViews:@[self.adCallToActionButton, self.adCoverMediaView]];
    
      // 4. Render the ad content onto the view
      self.adTitleLabel.text = self.nativeAd.advertiserName;
      self.adBodyLabel.text = self.nativeAd.bodyText;
      self.adSocialContextLabel.text = self.nativeAd.socialContext;
      self.sponsoredLabel.text = self.nativeAd.sponsoredTranslation;
      [self.adCallToActionButton setTitle:self.nativeAd.callToAction forState:UIControlStateNormal];
      self.adOptionsView.nativeAd = self.nativeAd; 
    }
  4. 控制可点击的区域

    为打造更优质的用户体验,并获得更理想的成效,建议您始终考虑控制可点击的广告区域,避免无意点击。请参阅 Audience Network SDK 政策页面,详细了解有关空白区域不可点击的规定。



  5. 选择设备作为构建目标并运行上述代码后,您应该会看到如下所示的结果:



在模拟器中投放广告时,应将设置更改为测试模式,以查看测试广告。详情请参阅如何使用测试模式

第 3 步:如何获取内容的宽高比与应用自然的宽度和高度

在上述示例中,广告的素材内容在 adCoverMediaView 中展示,其对象类型是 FBMediaView。在上一步骤中,我们展示了如何使用 FBMediaView 从指定的 FBNativeAd 对象加载素材内容。这一视图会取代手动加载封面图片。创建 FBMediaView 时,您可以通过在 Storyboard 中设置自动布局限制或者硬编码的方式来确定该对象的宽度和高度。但是,视图的宽度和高度可能不适合此后所下载广告的实际封面图片。为解决这个问题,以下示例显示了如何获取内容的宽高比与应用自然的宽度和高度:

  1. 声明视图控制器会执行 FBMediaViewDelegate 协议
    class ViewController: UIViewController, FBNativeAdDelegate, FBMediaViewDelegate {
      ...
    }
    @interface ViewController : UIViewController <FBNativeAdDelegate, FBMediaViewDelegate>
    ...
    @end

  2. 在加载原生广告时,将 FBMediaView 对象的委托设置为您的视图控制器
    func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
      adCoverMediaView.delegate = self
    }
    - (void)nativeAdDidLoad:(FBNativeAd *)nativeAd 
    {
      self.adCoverMediaView.delegate = self;
    }

  3. 在您的视图控制器中实现 mediaViewDidLoad 方法
    func mediaViewDidLoad(_ mediaView: FBMediaView) {
      let currentAspect = mediaView.frame.size.width / mediaView.frame.size.height
      print(currentAspect)
      
      let actualAspect = mediaView.aspectRatio
      print(actualAspect)
    }
    - (void)mediaViewDidLoad:(FBMediaView *)mediaView
    {
      CGFloat currentAspect = mediaView.frame.size.width / mediaView.frame.size.height;
      NSLog(@"current aspect of media view: %f", currentAspect);
      
      CGFloat actualAspect = mediaView.aspectRatio;
      NSLog(@"actual aspect of media view: %f", actualAspect);
    }

    mediaView.aspectRatio 将返回正 CGFloat;如果当前未加载广告,则返回 0.0。加载素材视图后,该对象的值就会生效。您可以通过简便的方法设置 FBMediaView 对象的宽度和高度,以便符合所加载的素材内容的宽高比。您可以调用 applyNaturalWidthapplyNaturalHeight 来更新 FBMediaView 对象的宽度和高度,以便符合素材内容的宽高比。

第 4 步:验证展示次数和点击量记录

您可以添加以下任意函数,用于处理原生广告关闭或用户点击原生广告的情况

func nativeAdDidClick(_ nativeAd: FBNativeAd) {
  print("Native ad was clicked.")
}

func nativeAdDidFinishHandlingClick(_ nativeAd: FBNativeAd) {
  print("Native ad did finish click handling.")
}

func nativeAdWillLogImpression(_ nativeAd: FBNativeAd) {
  print("Native ad impression is being captured.")
}
- (void)nativeAdDidClick:(FBNativeAd *)nativeAd
{
  NSLog(@"Native ad was clicked.");
}

- (void)nativeAdDidFinishHandlingClick:(FBNativeAd *)nativeAd
{
  NSLog(@"Native ad did finish click handling.");
}

- (void)nativeAdWillLogImpression:(FBNativeAd *)nativeAd
{
  NSLog(@"Native ad impression is being captured.");
}

第 5 步:广告无法显示时如何调试

在视图控制器中添加并实现以下函数,以便处理广告加载失败问题

func nativeAd(_ nativeAd: FBNativeAd, didFailWithError error: Error) {
  print("Native ad failed to load with error: \(error.localizedDescription)")
}
- (void)nativeAd:(FBNativeAd *)nativeAd didFailWithError:(NSError *)error
{
  NSLog(@"Native ad failed to load with error: %@", error);
}

第 6 步:在不自动缓存的情况下加载广告

  1. 强烈建议在所有情况下均默认开启素材缓存功能。但是,我们允许您替换默认设置。如果决定替换默认的素材缓存设置,请谨慎处理
    let nativeAd = FBNativeAd(placementID: "YOUR_PLACEMENT_ID")
    nativeAd.delegate = self
    nativeAd.loadAd(withMediaCachePolicy: .none)
    FBNativeAd *nativeAd = [[FBNativeAd alloc] initWithPlacementID:@"YOUR_PLACEMENT_ID"];
    nativeAd.delegate = self;
    [nativeAd loadAdWithMediaCachePolicy:FBNativeAdsCachePolicyNone];

  2. 首先,您需要手动下载原生广告的所有素材
    func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
      
      ...
      
      self.adCoverMediaView.delegate = self
      nativeAd.downloadMedia()
      self.nativeAd = nativeAd
      
      ...
    }
    - (void)nativeAdDidLoad:(FBNativeAd *)nativeAd
    {
      ...
    
      self.adCoverMediaView.delegate = self;
      [nativeAd downloadMedia];
      self.nativeAd = nativeAd;
    
      ...
    }

  3. 接下来,您应当只调用 registerViewForInteraction,并在完成 mediaViewDidLoad 回调后展示广告。您必须加载并展示所有素材,才能算作一次符合条件的展示
    func mediaViewDidLoad(_ mediaView: FBMediaView) {
      guard let nativeAd = nativeAd else {
        return
      }
      
      // 1. Register what views will be tappable and what the delegate is to notify when a registered view is tapped
      // Here only the call-to-action button and the media view are tappable, and the delegate is the view controller
      nativeAd.registerView(
        forInteraction: adUIView,
        mediaView: mediaView,
        iconView: adIconImageView,
        viewController: self,
        clickableViews: [adCallToActionButton, mediaView]
      )
        
      // 2. Render the ad content onto the view
      adTitleLabel.text = nativeAd.advertiserName
      adBodyLabel.text = nativeAd.bodyText
      adSocialContextLabel.text = nativeAd.socialContext
      sponsoredLabel.text = nativeAd.sponsoredTranslation
      adCallToActionButton.setTitle(nativeAd.callToAction, for: .normal)
      adOptionsView.nativeAd = nativeAd
    }
    - (void)mediaViewDidLoad:(FBMediaView *)mediaView 
    {
      if (!self.nativeAd) {
        return;
      }
    
      // 1. Register what views will be tappable and what the delegate is to notify when a registered view is tapped
      // Here only the call-to-action button and the media view are tappable, and the delegate is the view controller
      [self.nativeAd registerViewForInteraction:self.adUIView
                                      mediaView:mediaView
                                       iconView:self.adIconImageView
                              viewController:self
                             clickableViews:@[self.adCallToActionButton, mediaView]];
    
      // 2. Render the ad content onto the view
      self.adTitleLabel.text = self.nativeAd.advertiserName;
      self.adBodyLabel.text = self.nativeAd.bodyText;
      self.adSocialContextLabel.text = self.nativeAd.socialContext;
      self.sponsoredLabel.text = self.nativeAd.sponsoredTranslation;
      [self.adCallToActionButton setTitle:self.nativeAd.callToAction forState:UIControlStateNormal];
      self.adOptionsView.nativeAd = self.nativeAd; 
    }

后续步骤

  • 查看说明如何使用原生广告的代码示例。NativeAdSample 是 SDK 的一部分,可在 FBAudienceNetwork/samples 文件夹下找到。使用 Xcode 打开项目,然后在设备或模拟器上运行。

更多资源

入门指南

Audience Network 入门技术指南

代码示例

Audience Network 广告集成示例

常见问题

Audience Network 常见问题

原生广告模板

更简便的原生广告集成方法