Перейти к основному содержимому
Версия: 4.2.0

Руководство по интеграции

Полное руководство по интеграции BidMachine Plus iOS SDK. Примеры кода приведены на Swift и Objective-C — используйте переключатель языка в каждом блоке.

BidMachine Plus iOS SDK

BidMachine Plus предоставляет два пути спроса через один API:

РежимОписание
AdNetworkBidMachine работает как источник спроса с хедер-биддингом — самостоятельно или подключённым к сторонней медиации
MediationBidMachine выступает в роли самой платформы медиации, проводя аукцион по вашему спросу

Одни и те же классы рекламных юнитов работают в обоих режимах, выбор делается при инициализации:

SwiftObjective-C
BannerAdBMBannerAd
InterstitialAdBMInterstitialAd
RewardedAdBMRewardedAd

Эта страница охватывает установку SDK, инициализацию и загрузку рекламы. Доступны два пути установки: автоматизированный через ИИ-агенты для кодинга или ручная настройка с CocoaPods или Swift Package Manager.

Автоматизированная интеграция с ИИ-агентами для кодинга

Бандл BidMachine Plus SDK Agents поставляет переносимый навык интеграции для Claude Code, Codex и Gemini. Установите его для вашей среды выполнения:

/plugin marketplace add bidmachine/bidmachine-sdk-agents
/plugin install bidmachine-sdk-agents@bidmachine

Затем попросите вашего агента интегрировать BidMachine Plus — например:

Промпт
Integrate BidMachine Plus into my iOS app with interstitial, rewarded, and banner ads.

Встроенный навык управляет интеграцией: добавляет зависимость SDK, инициализирует в режиме AdNetwork или Mediation, подключает рекламные юниты и устанавливает флаги приватности (GDPR, CCPA, ATT), сохраняя любую существующую настройку рекламы.

Ручная установка

Требуется iOS 13.0+ и Xcode 16.4+. Импортируйте модуль как import BidMachinePlus (Swift) или @import BidMachinePlus; (Objective-C).

CocoaPods

Subspec Static используется по умолчанию и автоматически добавляет линкер-флаг -ObjC.

Podfile
platform :ios, '13.0'
use_frameworks!

target 'YourApp' do
pod 'BidMachinePlus' # default (Static)
# pod 'BidMachinePlus/Static'
# pod 'BidMachinePlus/Dynamic'
end

Swift Package Manager

  1. File → Add Package Dependencies
  2. URL: https://github.com/bidmachine/BidMachinePlus-SPM
  3. Выберите версию 0.0.1 или диапазон и добавьте продукт BidMachinePlus
  4. Добавьте -ObjC в Build Settings → Other Linker Flags
Package.swift
.package(url: "https://github.com/bidmachine/BidMachinePlus-SPM", from: "0.0.1")
// product: .product(name: "BidMachinePlus", package: "BidMachinePlus-SPM")

Настройка Info.plist

Разрешите произвольные загрузки, чтобы рекламные креативы могли отображаться:

Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

Вставьте массив SKAdNetworkItems — полный список ID сетей публикуется вместе с SDK.

Если вы собираете IDFA, добавьте описание использования ATT:

Info.plist
<key>NSUserTrackingUsageDescription</key>
<string>$(APP_NAME) needs your advertising identifier to deliver personalized ads.</string>

Инициализация

Вызовите BidMachine.instance(appKey:) один раз при запуске приложения, чтобы получить экземпляр SDK, затем вызовите initialize(config:completion:). Сохраните ссылку на экземпляр — вы будете передавать её в каждый конструктор рекламного юнита. Один и тот же app key всегда возвращает один и тот же экземпляр. Completion вызывается в главной очереди.

BidMachine Plus инициализируется в одном из двух режимов, выбираемом по integrationType, который вы передаёте в билдер.

Режим AdNetwork

BidMachine работает как рекламная сеть с хедер-биддингом. Когда он подключается к сторонней медиации, укажите эту платформу через сеттер медиатора, чтобы он мог конкурировать в вотерфолле.

let sdk = BidMachine.instance(appKey: "YOUR_APP_KEY")

let config = InitializationConfigBuilder(integrationType: .adNetwork)
.with(mediator: MediatorName.admob) // or MediatorName.levelPlay, MediatorName.max, a custom String
.with(loggingEnabled: true) // remove before release
.with(testModeEnabled: true) // remove before release
.build()

sdk.initialize(config: config) { status, error in
if let error { print("init failed: \(error.message)") }
}

MediatorName.admob / BMMediatorNameAdMob ("admob"), .levelPlay / BMMediatorNameLevelPlay ("level_play") и .max / BMMediatorNameMax ("max") — это предопределённые строковые константы; сеттер медиатора также принимает любую произвольную строку.

Режим Mediation

BidMachine выступает в роли самой платформы медиации, проводя аукцион по вашему спросу. Передайте тип медиации — стороннего медиатора объявлять не нужно:

let config = InitializationConfigBuilder(integrationType: .mediation)
.with(loggingEnabled: true) // remove before release
.with(testModeEnabled: true) // remove before release
.build()

BidMachine.instance(appKey: "YOUR_APP_KEY").initialize(config: config) { status, error in }

В обоих режимах классы рекламных юнитов предоставляют notifyWin / notifyLoss для сообщения результата раунда вотерфолла — см. Медиация.

Загружаете рекламу под серверную ставку? См. S2S биддинг для load(bidPayload:).

Интеграция рекламы

Все коллбэки жизненного цикла рекламы передают AdInfo / BMAdInfo, описывающий победившую рекламу:

СвойствоТип (Swift / Obj-C)Описание
placementIdString / NSString *ID плейсмента из дашборда BidMachine
priceDouble / doubleeCPM ÷ 1000 (например, 0.005 = $5 CPM)
precisionRevenuePrecisionОдно из .estimated, .exact, .unknown
info[String: String] / NSDictionaryМетаданные сети. Известные ключи: networkName, dsp, ecpm

Читайте победившую сеть через adInfo.info["networkName"], а доход на показ — через adInfo.price.

adInfo.precision описывает, насколько надёжна эта цена:

SwiftObj-CЗначение
.exactRevenuePrecisionExactЦена аукциона в реальном времени — доверяйте при отчётности
.estimatedRevenuePrecisionEstimatedОценка по историческим данным — считайте приблизительной
.unknownRevenuePrecisionUnknownДостоверность не может быть определена

Все коллбэки делегата срабатывают в главном потоке, поэтому вы можете обновлять UI прямо из них. В каждом делегате обязательны только didLoadAd и didFailToLoadAd — остальные необязательны.

Реклама Interstitial

Полноэкранная реклама. Создайте один раз, загрузите, затем показывайте, когда она готова. Перезагружайте из didDismiss, чтобы держать рекламу готовой к следующему показу.

MainViewController.swift
class MainViewController: UIViewController, InterstitialDelegate {
private var interstitialAd: InterstitialAd!

private func createInterstitialAd() {
interstitialAd = InterstitialAd(sdk, placementId: "YOUR_PLACEMENT_ID")
interstitialAd.delegate = self
interstitialAd.load()
}

private func showInterstitialAd() {
if interstitialAd.isLoaded {
interstitialAd.show(from: self)
} else {
print("Interstitial ad not ready yet")
}
}

// InterstitialDelegate
func didLoadAd(adInfo: AdInfo) {
print("Interstitial loaded from \(adInfo.info["networkName"] ?? "?")")
}
func didFailToLoadAd(adInfo: AdInfo?, error: BidMachineError) {
print("Interstitial load failed: \(error.message)")
}
func didShowAd(adInfo: AdInfo) {}
func didFailToShowAd(adInfo: AdInfo?, error: BidMachineError) {
print("Interstitial show failed: \(error.message)")
}
func didClick(adInfo: AdInfo) {}
func didDismiss(adInfo: AdInfo) {
interstitialAd.load() // reload for next show
}
func didExpire(adInfo: AdInfo) {}
func didPayRevenue(adInfo: AdInfo) {
print("Interstitial revenue: \(adInfo.price) from \(adInfo.info["networkName"] ?? "?")")
}
}
КоллбэкОписание
didLoadAdРеклама загружена и готова к показу
didFailToLoadAdРеклама не загрузилась
didShowAdРеклама отображается на весь экран
didFailToShowAdРеклама не отобразилась
didClickПользователь нажал на рекламу
didDismissПользователь закрыл рекламу
didExpireСрок действия рекламы истёк до показа
didPayRevenueЗарегистрирован оплачиваемый показ
примечание

У InterstitialAd и RewardedAd нет метода destroy() — чтобы освободить полноэкранную рекламу, отпустите ссылку на неё. (BannerAd предоставляет destroy().)

Реклама Rewarded

Тот же жизненный цикл, что у interstitial, плюс коллбэк didReceiveReward, когда пользователь зарабатывает награду. RewardedDelegate наследуется от InterstitialDelegate.

MainViewController.swift
class MainViewController: UIViewController, RewardedDelegate {
private var rewardedAd: RewardedAd!

private func createRewardedAd() {
rewardedAd = RewardedAd(sdk, placementId: "YOUR_PLACEMENT_ID")
rewardedAd.delegate = self
rewardedAd.load()
}

private func showRewardedAd() {
if rewardedAd.isLoaded {
rewardedAd.show(from: self)
}
}

// RewardedDelegate
func didLoadAd(adInfo: AdInfo) {}
func didReceiveReward(adInfo: AdInfo, reward: Reward?) {
print("Reward earned: \(reward?.amount ?? 0) \(reward?.label ?? "")")
// grant reward to the user
}
func didFailToLoadAd(adInfo: AdInfo?, error: BidMachineError) {
print("Rewarded load failed: \(error.message)")
}
func didDismiss(adInfo: AdInfo) {
rewardedAd.load() // reload for next show
}
func didPayRevenue(adInfo: AdInfo) {
print("Rewarded revenue: \(adInfo.price) from \(adInfo.info["networkName"] ?? "?")")
}
}

didReceiveReward добавляется к набору коллбэков interstitial. Объект Reward / BMReward предоставляет label: String и amount: Int.

Баннеры

BannerAd / BMBannerAd — это UIView. Добавьте его в свою разметку или вызовите show(at:), чтобы закрепить его у края экрана. Он одноразовый — он не обновляется автоматически.

Размер (Swift)Obj-CРазмерыСценарий
.bannerBMBannerAdSize.banner320 × 50Стандартный баннер
.leaderboardBMBannerAdSize.leaderboard728 × 90Планшеты
.mrecBMBannerAdSize.mrec300 × 250Средний прямоугольник
.adaptive(width:maxHeight:)+adaptiveWithWidth:maxHeight:произвольныеАдаптивная разметка
подсказка

Используйте BannerAdSize.getMaxAdaptiveHeight(width:) (+getMaxAdaptiveHeightWithWidth: в Obj-C), чтобы вычислить maxHeight для адаптивных баннеров. width и maxHeight имеют тип UInt32.

Ручной баннер

Зарезервируйте хост-UIView, затем прикрепите загруженный баннер к нему внутри didLoadAd:

MainViewController.swift
class MainViewController: UIViewController, BannerDelegate {
@IBOutlet private var adContainer: UIView!
private var bannerAd: BannerAd!

private func createBannerAd() {
bannerAd = BannerAd(sdk, placementId: "YOUR_PLACEMENT_ID", size: .banner)
bannerAd.delegate = self
bannerAd.load()
}

deinit { bannerAd?.destroy() }

// BannerDelegate
func didLoadAd(adInfo: AdInfo) {
adContainer.addSubview(bannerAd)
}
func didFailToLoadAd(adInfo: AdInfo?, error: BidMachineError) {
print("Banner load failed: \(error.message)")
}
func didShowAd(adInfo: AdInfo) {}
func didFailToShowAd(adInfo: AdInfo?, error: BidMachineError) {}
func didClick(adInfo: AdInfo) {}
func didExpire(adInfo: AdInfo) {}
func didPayRevenue(adInfo: AdInfo) {
print("Banner revenue: \(adInfo.price) from \(adInfo.info["networkName"] ?? "?")")
}
}
КоллбэкОписание
didLoadAdРеклама загружена и готова к добавлению в superview
didFailToLoadAdРеклама не загрузилась
didShowAdРеклама видна на экране, показ отслежен
didFailToShowAdРеклама не отобразилась
didClickПользователь нажал на рекламу
didExpireСрок действия рекламы истёк до показа
didPayRevenueЗарегистрирован оплачиваемый показ

Позиционированный баннер

Вызовите show(at:) на загруженном баннере, чтобы закрепить его у одного из краёв ниже. SDK определяет хост-вью внутренне (rootViewController ключевого окна, с фолбэком на верхний презентованный VC) — хост-вью в месте вызова не требуется. Вызовите hide(), чтобы убрать его.

ПозицияSwiftObj-C
Сверху.horizontalTopBMBannerPositionHorizontalTop
Снизу.horizontalBottomBMBannerPositionHorizontalBottom
Слева.verticalLeftBMBannerPositionVerticalLeft
Справа.verticalRightBMBannerPositionVerticalRight
// In didLoadAd:
bannerAd.show(at: .horizontalBottom) // position defaults to .horizontalBottom

// Later:
bannerAd.hide() // detaches the view; show(at:) can re-display it
bannerAd.destroy()

.verticalLeft / .verticalRight поворачивают баннер на 90° в боковую полосу (только неадаптивные размеры — адаптивные баннеры откатываются к разметке horizontal-bottom). hide() только отсоединяет вью; он не вызывает destroy().

Дополнительные данные паблишера

Прикрепляйте произвольные пары key → value, передаваемые вместе с bid-запросом. API имеет одинаковую форму на двух уровнях:

ОбластьГде вызыватьПрименяется к
На весь SDKsdk.addExtraКаждому аукциону этого экземпляра
На рекламный юнит<AdUnit>.addExtraТолько аукционам этого плейсмента

Передача nil в качестве значения удаляет ключ. Во время загрузки extras рекламного юнита накладываются поверх значений на весь SDK — ключи рекламного юнита побеждают при коллизии.

На весь SDK

sdk.addExtra("whale", forKey: "user_segment")
let all: [String: String] = sdk.extras
sdk.addExtra(nil, forKey: "user_segment") // remove

На рекламный юнит

Доступно на BannerAd, InterstitialAd и RewardedAd, с той же сигнатурой addExtra(_:forKey:), что и у вызова на весь SDK:

interstitialAd.addExtra("level_complete", forKey: "placement_context")
let adExtras: [String: String] = interstitialAd.extras