OMNIBOX iOS SDK
Интеграция баннерной рекламы в iOS-приложение через Prebid Mobile SDK 3.3.1 и SwiftUI.
Архитектура
┌─────────────────────────────────────────────────────┐
│ ContentView (SwiftUI) │
│ └─ IABoxBanner (UIViewRepresentable) │
│ └─ IABoxBannerContainerView (UIView) │
│ ├─ BannerView (Prebid) — bid request │
│ └─ WKWebView — rendering HTML creative │
└─────────────────────────────────────────────────────┘
PrebidMobile.BannerViewsends an OpenRTB bid request to Prebid Server- Server returns bid response with HTML/JS creative (adm)
WKWebViewrenders the received adm
Why WKWebView instead of PrebidMobile built-in renderer?
The OMNIBOX server returns HTML/JS creative with its own SDK (adboxsdk.new.js) containing event tracking in JavaScript, not at the OpenRTB protocol level. The built-in PrebidMobile renderer expects event trackers in OpenRTB format (burl,eventtrackers), so it cannot render such creative. WKWebView renders HTML as-is.
Требования
- iOS 14.0+
- Xcode 15.0+
- Swift 5.9+
Установка
1. Добавление Prebid Mobile SDK
PrebidMobile — сторонний open-source пакет от Prebid.org, хостится на GitHub.
В Xcode: File → Add Package Dependencies, введите URL:
https://github.com/prebid/prebid-mobile-ios
Выберите только:
- ✅
PrebidMobile
Не добавляйте PrebidMobileAdMobAdapters, PrebidMobileGAMEventHandlers, PrebidMobileMAXAdapters — они не нужны для standalone режима и тянут Google Mobile Ads SDK.
2. Настройка параметров
В файле IABoxBannerView.swift укажите параметры вашего аккаунта:
let bannerConfigID = "test_banner" // Config ID placement
let accountID = "com.iabox.ios-sdk-test-1" // Account ID
let serverURL = "https://ia.box/ads/prebid" // Prebid Server URL
3. App Tracking Transparency (IDFA)
Для передачи реального deviceId (IDFA) на рекламный сервер необходимо получить разрешение пользователя через App Tracking Transparency.
Без разрешения сервер получает 00000000-0000-0000-0000-000000000000 вместо реального идентификатора.
ATT и инициализация SDK — независимые процессы. SDK можно инициализировать в любой момент.
Шаг 1. Добавьте описание в Info.plist
In Build Settings of the project (or directly in Info.plist) add key NSUserTrackingUsageDescription:
<key>NSUserTrackingUsageDescription</key>
<string>This identifier is used to deliver personalized ads.</string>
Or via Xcode Build Settings:
INFOPLIST_KEY_NSUserTrackingUsageDescription = "This identifier is used to deliver personalized ads."
Шаг 2. Запросите разрешение в коде
Запрос ATT должен вызываться после появления UI — иначе системный диалог не отобразится.
Вариант A — scenePhase (рекомендуемый для SwiftUI)
Запрос при переходе сцены в .active. Гарантирует, что окно приложения уже отображено:
import AppTrackingTransparency
import AdSupport
@main
struct MyApp: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { phase in
if phase == .active {
if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
ATTrackingManager.requestTrackingAuthorization { _ in }
}
}
}
}
}
}
Важно: applicationDidBecomeActive не вызывается в SwiftUI scene-based приложениях. Используйте scenePhase.
Вариант B — UIKit AppDelegate
Для UIKit-приложений (без scene lifecycle):
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidBecomeActive(_ application: UIApplication) {
if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
ATTrackingManager.requestTrackingAuthorization { _ in }
}
}
}
Поведение в зависимости от статуса ATT
| ATT status | IDFA | Описание |
|---|---|---|
.authorized | Real UUID | Персонализированная реклама |
.denied | 00000000-... | Контекстуальная реклама |
.restricted | 00000000-... | Контекстуальная реклама |
.notDetermined | 00000000-... | Необходимо запросить разрешение |
Тестирование на симуляторе: для повторного показа ATT-диалога удалите приложение с симулятора и запустите заново.
4. Сборка и запуск
Соберите и запустите проект: Cmd+R
Структура проекта
ios-sdk-test/
├── ios-sdk-test/
│ ├── ios_sdk_testApp.swift # Entry point (SwiftUI App)
│ ├── ContentView.swift # UI with banner load buttons
│ ├── IABoxBannerView.swift # Prebid + WKWebView wrapper
│ └── Assets.xcassets/ # Resources
├── ios-sdk-test.xcodeproj/ # Xcode project
└── README.md
Как работает интеграция
1. Инициализация SDK
Prebid.shared.prebidServerAccountId = accountID
Prebid.shared.timeoutMillis = 10000
Prebid.shared.shareGeoLocation = true
try? Prebid.initializeSDK(serverURL: serverURL) { status, error in
// Handle initialization result
}
initializeSDK проверяет {serverURL}/status. Если этот endpoint не настроен (404) — это не критично, bid requests всё равно будут отправляться на /openrtb2/auction.
2. Bid Request
let bannerView = BannerView(
frame: CGRect(origin: .zero, size: adSize),
configID: configID,
adSize: adSize
)
bannerView.delegate = self
bannerView.loadAd() // → POST {serverURL}/openrtb2/auction
3. Рендеринг креатива в WKWebView
При получении bid response извлекается adm (HTML-креатив) и загружается в WKWebView:
func bannerView(_ bannerView: BannerView, didReceiveAdWithAdSize adSize: CGSize) {
if let adm = bannerView.lastBidResponse?.winningBid?.adm {
renderAdm(adm) // Loads HTML into WKWebView
}
}
4. SwiftUI обёртка
struct IABoxBanner: UIViewRepresentable {
@ObservedObject var viewModel: BannerViewModel
let configID: String
let adSize: CGSize
var onStatusUpdate: ((String) -> Void)?
func makeUIView(context: Context) -> IABoxBannerContainerView { ... }
func updateUIView(_ uiView: IABoxBannerContainerView, context: Context) { ... }
}
5. Обработка кликов
Клики по рекламе обрабатываются через WKNavigationDelegate и WKUIDelegate. Ссылки перехватываются в decidePolicyFor и открываются в Safari. window.open() из JS перехватывается в createWebViewWith и открывается в Safari.
Формат ответа сервера (adm)
Сервер iaBox возвращает HTML/JS креатив. Трекинг событий (impression, click, viewability) выполняется внутри adboxsdk.new.js на стороне WebView.
<script src="https://dcdn.adbox.ru/adboxsdk.new.js" async></script>
<script>
window.AdBox.push({
"format": "simple",
"srcType": "url",
"src": "https://ia.box/ads/markup?bid=...&imp=...",
"target": "#slot-...",
"size": {"w": 300, "h": 250},
"track": {
"impression": ["https://ia.box/track/impression?..."],
"click": ["https://ia.box/track/click?..."],
"view": ["https://ia.box/track/viewable?..."],
"load": ["https://ia.box/track/loaded?..."],
"error": ["https://ia.box/track/error?..."]
}
})
</script>
<div id="slot-..."></div>
Troubleshooting
No such module 'PrebidMobile'
Проверьте, что Swift Package добавлен: Project → Package Dependencies. Убедитесь, что добавлен только PrebidMobile, без дополнительных адаптеров.
SDK status check failed
Endpoint /status не настроен на сервере — это допустимо. Bid requests будут работать через /openrtb2/auction.
Creative model must be provided with event tracker
Лог встроенного рендерера PrebidMobile — можно игнорировать. Креатив рендерится через WKWebView, минуя встроенный рендерер.
The Google Mobile Ads SDK was initialized without an application ID
Добавлены лишние пакеты (PrebidMobileAdMobAdapters и т.д.). Удалите их, оставьте только PrebidMobile.
deviceId = 00000000-0000-0000-0000-000000000000
Пользователь не дал разрешение на трекинг (ATT). Проверьте NSUserTrackingUsageDescription в Info.plist. Убедитесь, что ATTrackingManager.requestTrackingAuthorization вызывается после появления UI. На симуляторе: удалите приложение и запустите заново.
Баннер не отображается
Проверьте логи Xcode Console на наличие сообщений loadBanner(), Bid received, Rendering adm. Убедитесь, что configID существует на сервере. Проверьте доступность сервера: curl https://ia.box/ads/prebid/openrtb2/auction