ToBid iOS 接入指南
本文档指导开发者在 iOS 端将优聚智汇 SDK 以**自定义广告网络(Custom Adapter)**形式接入 ToBid(Sigmob WindMill)聚合平台。
阅读前置
请先阅读 ToBid 自定义接入概述,了解反向集成模式、工作原理、后台配置与常见问题。本文仅介绍 iOS 端的依赖引入、dead-strip 防护、SDK 初始化与广告加载。
依赖引入
1. 引入优聚 SDK 核心库
确保工程已通过 SPM 引入优聚智汇 SDK 核心库(UjuAdSdk),详见 iOS 集成说明。
2. 引入优聚 ToBid 适配器
优聚 ToBid 适配器以独立 SPM Package 形式提供,包名为 ToBidAdapter,依赖 UjuAdSdk 核心库。
在 Xcode 中通过 File → Add Packages → Add Local... 添加 ToBidAdapter 目录,或在 Package.swift 中添加本地依赖:
// Package.swift
dependencies: [
// 依赖优聚 SDK 核心库(位于同级目录)
.package(path: "../"),
// 依赖 ToBid 适配器
.package(path: "../Adapters/ToBidAdapter/")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "UjuAdSdk", package: "UjuAdSdk"),
.product(name: "ToBidAdapter", package: "ToBidAdapter")
]
)
]3. 引入 ToBid 聚合 SDK
ToBid(Sigmob WindMill)SDK 需通过 CocoaPods 或 SPM 单独引入,具体引入方式参考 Sigmob 官方文档。适配器在编译期不依赖 WindMillSDK,仅在运行时由 WindMillSDK 通过 ObjC 运行时动态发现并调用适配器类。
防止 dead-strip(必须)
WindMillSDK 通过 ObjC 运行时(NSClassFromString)动态发现优聚 ToBid 适配器类。由于适配器在编译期不被任何代码直接引用,链接器可能会将其视为无用代码而移除(dead-strip),导致运行时找不到适配器。
必须在 App 启动时调用一次 ToBidAdapter.ensureLinked(),确保适配器模块被链接进宿主二进制:
import UIKit
import ToBidAdapter
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 确保 ToBidAdapter 模块被链接进二进制
// WindMillSDK 通过运行时发现 Custom*Adapter 类,需保证模块代码未被 dead-strip
_ = ToBidAdapter.ensureLinked()
// 初始化 ToBid SDK
initToBidSdk()
return true
}
}不可省略
若忘记调用 ensureLinked(),WindMillSDK 在运行时将无法发现优聚适配器,表现为优聚 ADN 永远无法初始化、广告位无法加载。
ToBid SDK 初始化
开发者只需初始化 ToBid SDK,优聚 SDK 的初始化由 ToBid 在启动时自动触发(通过适配器的初始化入口)。
在 AppDelegate.application(_:didFinishLaunchingWithOptions:) 中初始化 ToBid:
import UIKit
import ToBidAdapter
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 1. 确保 ToBidAdapter 模块被链接进二进制
_ = ToBidAdapter.ensureLinked()
// 2. 初始化 ToBid SDK
initToBidSdk()
return true
}
// MARK: - 初始化 ToBid SDK
/// 初始化 ToBid 聚合 SDK
///
/// 步骤:
/// 1. 获取 WindMillAd 单例
/// 2. 配置个性化推荐、Debug、成年等参数
/// 3. 调用 startWithAppId 启动 SDK,传入 AppId 和初始化回调
private func initToBidSdk() {
print("[ToBidDemo] initToBidSdk 开始")
// 接入真实 WindMillSDK 后的完整实现:
// let ads = WindMillAd.sharedAds()
// // 是否成年(可选参数,默认是成年用户)
// ads.setAdult(true)
// // 是否开启个性化推荐(可选参数,默认开启)
// ads.setPersonalizedAdvertisingOn(true)
// // 开启 Debug 日志(调试阶段建议开启)
// ads.setDebugEnable(true)
//
// // 启动 ToBid SDK,传入 ToBid 后台分配的 AppId
// ads.startWithAppId(self, ToBidDemoConfig.TOBID_APP_ID, listener: { success, errorMsg in
// if success {
// print("ToBid SDK 初始化成功")
// } else {
// print("ToBid SDK 初始化失败: \(errorMsg ?? "未知错误")")
// }
// })
}
}优聚 SDK 无需单独初始化
ToBid SDK 启动后会自动触发优聚 SDK 的 init + start 流程,开发者无需也不应调用 UjuAdSdk.shared.init() / UjuAdSdk.shared.start()。
广告加载示例
以下以激励视频为例,展示通过 ToBid 标准接口加载广告的完整流程。开屏、插屏、横幅、原生广告的调用方式类似,仅广告对象类名不同。
import UIKit
// import WindMillSDK // 接入真实 WindMillSDK 后引入
class RewardAdViewController: UIViewController {
// MARK: - 属性
/// 日志输出文本视图
private let logTextView = UITextView()
/// 展示按钮
private let showButton = UIButton(type: .system)
/// 广告是否已加载就绪
private var isReady = false
/// ToBid 激励视频广告对象(WindMillSDK 类型)
private var rewardAd: AnyObject?
// MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
title = "激励视频广告测试"
view.backgroundColor = .white
setupUI()
}
// MARK: - 加载广告
@objc private func loadAd() {
appendLog("开始加载激励视频广告: placementId=\(ToBidDemoConfig.REWARD_PLACEMENT_ID)")
isReady = false
updateShowButton()
// 接入真实 WindMillSDK 后的实际调用:
// let request = WMRewardAdRequest(ToBidDemoConfig.REWARD_PLACEMENT_ID, "", nil)
// rewardAd = WMRewardAd(self, request)
// rewardAd?.setRewardedAdListener(self)
// rewardAd?.loadAd()
}
// MARK: - 展示广告
@objc private func showAd() {
// 空指针检查:广告未就绪不展示
guard isReady else {
appendLog("广告未就绪,无法展示")
return
}
appendLog("展示激励视频广告")
// 接入真实 WindMillSDK 后:rewardAd?.show(self, nil)
}
// MARK: - 资源释放
deinit {
// 销毁广告对象,释放资源
// rewardAd?.destroy()
}
// MARK: - UI 布局(略)
private func setupUI() {
// UI 布局代码略,开发者按需实现
}
private func updateShowButton() {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.showButton.isEnabled = self.isReady
}
}
private func appendLog(_ message: String) {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.logTextView.text.append(message + "\n")
}
}
}
// MARK: - ToBid 激励视频监听回调(接入真实 WindMillSDK 后实现)
/// 接入真实 WindMillSDK 后,让 ViewController 符合 WMRewardAdListener 协议:
///
/// extension RewardAdViewController: WMRewardAdListener {
/// func onVideoAdLoadSuccess(_ placementId: String?) {
/// appendLog("广告加载成功: \(placementId ?? "")")
/// isReady = true
/// updateShowButton()
/// }
///
/// func onVideoAdLoadError(_ error: WindMillError?, placementId: String?) {
/// appendLog("广告加载失败: \(error?.errorCode ?? 0)-\(error?.message ?? "")")
/// }
///
/// func onVideoAdPlayStart(_ adInfo: AdInfo?) {
/// appendLog("广告开始播放")
/// }
///
/// func onVideoAdPlayEnd(_ adInfo: AdInfo?) {
/// appendLog("广告播放结束")
/// }
///
/// func onVideoAdClicked(_ adInfo: AdInfo?) {
/// appendLog("广告被点击")
/// }
///
/// func onVideoRewarded(_ adInfo: AdInfo?, rewardInfo: WMRewardInfo?) {
/// appendLog("获得奖励: isReward=\(rewardInfo?.isReward() ?? false)")
/// // 在此发放应用内奖励
/// }
///
/// func onVideoAdClosed(_ adInfo: AdInfo?) {
/// appendLog("广告关闭")
/// isReady = false
/// updateShowButton()
/// }
/// }各广告类型对应协议
| 广告类型 | ToBid 广告类 | 监听协议 |
|---|---|---|
| 开屏 | WMSplashAd | WMSplashAdListener |
| 激励视频 | WMRewardAd | WMRewardAdListener |
| 插屏 | WMInterstitialAd | WMInterstitialAdListener |
| 横幅 | WMBannerAd | WMBannerAdListener |
| 原生 | WMNativeAd | WMNativeAdListener |
模板渲染模式
优聚原生广告采用模板渲染模式,由 SDK 内部渲染广告视图并绑定到 ToBid 提供的容器中。开发者无需自行绘制原生广告视图,NativeAdData 的字段(title/desc/iconUrl 等)可能为空。
适配器架构说明
优聚 ToBid 适配器以独立 SPM Package(ToBidAdapter)形式提供,实现 WindMillSDK 的 AWMCustom*Adapter 协议:
- 适配器入口:
ToBidAdapter模块提供ensureLinked()方法防止 dead-strip,并提供版本号查询 - 初始化适配器:实现 ToBid 的配置适配器协议,在 ToBid 启动时解析后台
CustomInfo(appId/appKey/channel),完成优聚 SDK 的init+start流程,并通过 bridge 回调通知 ToBid 初始化结果 - 广告适配器:每种广告类型(开屏/激励/插屏/横幅/原生)对应一个独立的适配器类,实现 ToBid 的
AWMCustom*Adapter协议,负责广告的加载、展示、销毁与事件回调转发 - 初始化等待机制:适配器内部维护初始化状态追踪,各广告适配器在
loadAd入口会等待优聚 SDK 初始化完成后再执行实际加载,避免 "no strategy" 错误 - 配置解析:统一解析 ToBid 后台下发的
CustomInfoJSON 字符串,提取 appId/appKey/channel(ADN 级别)与 placementId(广告位级别) - Bridge 隔离:适配器在编译期不依赖 WindMillSDK,通过运行时机制调用 bridge 回调;接入真实 WindMillSDK 后可将 bridge 类型从运行时调用改为具体协议方法调用
内部实现无需关注
适配器内部的所有类、方法与状态机均为 SDK 内部实现细节,开发者无需直接调用。开发者只需通过 ToBid 标准接口(WindMillAd / WMRewardAd 等)使用广告,并在 App 启动时调用 ToBidAdapter.ensureLinked() 即可。
相关链接
- ToBid 自定义接入概述 — 反向集成模式、工作原理、后台配置、常见问题
- Android 接入指南 — Android 端接入步骤
- 自定义广告平台概述 — 反向集成概念说明
- iOS 集成说明 — 优聚 iOS SDK 标准集成(参考)
