广告信息流

广告信息流是由一系列广告组成的单元。信息流可以作为应用的主要内容添加,或者添加到现有内容之后。信息流可能包含数十条广告,而这些广告会按顺序加载(一次加载多个广告)。

本指南介绍如何在 iOS 应用中集成广告信息流。除代码示例与步骤外,还包含格式使用建议及更多资源链接。

外观

前提条件

  1. 请按照 快速入门 中描述的 SDK 集成步骤进行操作。
  2. 提前 初始化 您的广告 SDK。
  3. 确保您运行的是最新的 Yandex Mobile Ads SDK 版本。如果您使用聚合,请同时确保您运行的是最新版本的 统一构建

实施

集成广告信息流的主要步骤:

  1. 通过 FeedAdAppearance 配置信息流外观。
  2. 创建 FeedAd 对象,设置 delegate,并实现所需的 FeedAdDelegate 方法。
  3. 加载广告。
  4. 创建 FeedAdCollectionViewAdapter 并绑定到 UICollectionView

广告信息流集成说明

  • 所有 Yandex Mobile Ads SDK 方法须在主线程调用。
  • 在展示信息流的界面可见期间,请对 FeedAdFeedAdCollectionViewAdapter 保持强引用。

外观

创建 FeedAdAppearance 配置对象。

可用参数:

  • cardWidth(必填):展示广告宽度,单位为 point。通常取屏幕宽度减去左右边距。
  • cardCornerRadius:展示广告圆角半径,单位为 point。
let feedMargin: CGFloat = 24
let cardWidth = view.bounds.width - 2 * feedMargin
let appearance = FeedAdAppearance(cardWidth: cardWidth, cardCornerRadius: 16)

加载广告

使用 Yandex Advertising Network 界面获取的广告位 ID(adUnitId)创建 FeedAd

可通过 AdRequest 扩展请求,传入用户兴趣、页面上下文、位置等数据,有助于提升广告质量。详见广告定位

设置 delegate,并实现 FeedAdDelegate 以处理加载与广告事件:

final class FeedAdViewController: UIViewController {
    private var feedAd: FeedAd?

    func loadAd() {
        let request = AdRequest(adUnitID: "R-M-XXXXXX-Y")
        let appearance = FeedAdAppearance(cardWidth: view.bounds.width)
        let feedAd = FeedAd(requestConfiguration: request, appearance: appearance)
        feedAd.delegate = self
        self.feedAd = feedAd
        feedAd.loadAd()
    }
}

extension FeedAdViewController: FeedAdDelegate {
    func feedAdDidLoad(_ feedAd: FeedAd) {
        // Called when an ad is successfully loaded
    }

    func feedAd(_ feedAd: FeedAd, didFailToLoadWithError error: Error) {
        // Called when ad loading fails
    }

    func feedAdDidClick(_ feedAd: FeedAd) {
        // Called when the user taps the ad
    }

    func feedAd(_ feedAd: FeedAd, didTrackImpression impressionData: ImpressionData?) {
        // Called when an impression is tracked
    }

    func feedAdDidUpdateDataSource(_ feedAd: FeedAd) {
        // Called when new ads are available — reload collection view
        collectionView.reloadData()
    }
}

展示信息流

使用 FeedAdCollectionViewAdapter 作为 UICollectionViewdataSourcedelegate

在绑定适配器前,调用 registerCells(in:) 注册单元格类型,且须在设置 dataSourcedelegate 之前完成。

作为主列表

将适配器的 dataSourcedelegate 赋给 UICollectionView

final class FeedAdViewController: UIViewController {
    private let collectionView = UICollectionView(
        frame: .zero,
        collectionViewLayout: UICollectionViewFlowLayout()
    )
    private var feedAdAdapter: FeedAdCollectionViewAdapter?

    func setupAdapter() {
        guard let feedAd else { return }
        let adapter = FeedAdCollectionViewAdapter(feedAd: feedAd)
        adapter.registerCells(in: collectionView)
        collectionView.dataSource = adapter.dataSource
        collectionView.delegate = adapter.delegate
        feedAdAdapter = adapter
    }
}

与现有内容并存

若已自行实现 UICollectionViewDataSource,可将信息流分区委托给适配器:

final class FeedAdViewController: UIViewController {
    private enum Section: Int, CaseIterable {
        case content
        case feed
    }

    private var contentItems: [ContentItem] = []
    private var feedAdAdapter: FeedAdCollectionViewAdapter?

    func setupAdapter() {
        guard let feedAd else { return }
        let adapter = FeedAdCollectionViewAdapter(feedAd: feedAd)
        adapter.registerCells(in: collectionView)
        feedAdAdapter = adapter

        collectionView.dataSource = self
        collectionView.delegate = self
    }
}

extension FeedAdViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        Section.allCases.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch Section(rawValue: section) {
        case .content:
            return contentItems.count
        case .feed:
            return feedAdAdapter?.dataSource.collectionView(collectionView, numberOfItemsInSection: section) ?? 0
        case .none:
            return 0
        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        switch Section(rawValue: indexPath.section) {
        case .content:
            // Return your content cell
            return dequeueContentCell(for: indexPath)
        case .feed:
            return feedAdAdapter?.dataSource.collectionView(collectionView, cellForItemAt: indexPath)
                ?? UICollectionViewCell()
        case .none:
            return UICollectionViewCell()
        }
    }
}

extension FeedAdViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAt indexPath: IndexPath
    ) -> CGSize {
        switch Section(rawValue: indexPath.section) {
        case .feed:
            return feedAdAdapter?.delegate.collectionView?(
                collectionView,
                layout: collectionViewLayout,
                sizeForItemAt: indexPath
            ) ?? .zero
        default:
            return CGSize(width: collectionView.bounds.width, height: 80)
        }
    }
}

测试广告信息流集成

使用演示广告单元

要验证广告信息流集成并测试应用,请使用测试广告。

为确保每次广告请求都返回测试广告,我们提供了专用的演示广告位 ID,可用于检查集成是否正确。

演示用 adUnitIddemo-feed-yandex

重要

在将应用发布到商店之前,请将演示广告位 ID 替换为在 Yandex Advertising Network 界面中获取的真实 ID。

完整的演示广告位 ID 列表见用于测试的演示广告单元

验证集成

您可以使用本机控制台工具测试广告集成。

要查看详细日志,请调用 YMAMobileAds 类的 enableLogging 方法。

YMAMobileAds.enableLogging()

要查看 SDK 日志,请前往控制台工具并设置 Subsystem = com.mobile.ads.ads.sdk。您还可以按类别和错误级别过滤日志。

如果您在集成广告时遇到问题,您将获得有关问题的详细报告以及如何解决这些问题的建议。

更多资源