主题
引入依赖
文档版本 v1.0.0
本页对应 iOS SDK 1.0.0,与离线包 docs/ 目录里的同一份文档内容一致。其他版本见文档中心。
iOS SDK 通过 CocoaPods 分发。平台维护一个私有源,两家广告平台的 SDK 由 CocoaPods 从其官方源拉取,不随平台的包分发(两家的开发者协议不允许第三方转发其 SDK)。
不提供 Swift Package Manager 分发
两家广告平台的 iOS SDK 目前都未找到公开可解析的 SPM 分发。SPM 包里只能放 AdMixCore、放不进任何适配器, 装上也出不了广告,所以 iOS SDK 只以 CocoaPods 分发(或手工集成 xcframework,见下文「手工集成」)。 两家放出公开的 SPM 分发后,平台再补上这一通道。 以 SPM 为主的工程可以单独为广告引入 CocoaPods,两者能在同一工程里共存。
CocoaPods 方式
配置源
Podfile 顶部加入两个源,均为公开只读,不需要账号密码:
ruby
source 'https://cdn.cocoapods.org/' # CocoaPods 官方源(两家广告平台的 SDK 在这里)
source 'https://admin.maemi.cn/cocoapods/' # AdMix写了任何一个 source 就必须把官方源也写上
Podfile 里一个 source 都不写时 CocoaPods 默认用官方源;只要写了 AdMix 的源, 默认值就失效。漏掉官方源的表现是 Unable to find a specification for 'Ads-CN', 而不是「广告少一家」。
声明依赖
推荐全家桶,一行:
ruby
platform :ios, '12.0'
target 'YourApp' do
pod 'AdMix', '1.0.0' # 聚合核心 + 穿山甲 + 优量汇
end只接哪家就写哪几个子模块,不写的那家连同它的广告 SDK 完全不进包:
| 写法 | 包含 | 最小工程 .app 体积(arm64,Release,实测) |
|---|---|---|
pod 'AdMix', '1.0.0' | Core + CSJ + GDT | 约 41.7 MB |
pod 'AdMix', '1.0.0', :subspecs => ['Core', 'CSJ'] | 聚合核心 + 穿山甲 | 约 27.1 MB |
pod 'AdMix', '1.0.0', :subspecs => ['Core', 'GDT'] | 聚合核心 + 优量汇 | — |
体积是未压缩的 .app 目录大小,App Store 下载大小会小于这个值。
版本号建议写成精确值。Core 与适配器子模块的版本由同一个 pod 统一管理, 不会出现「核心 1.1.0 + 适配器 1.0.0」这种平台从没验证过的组合。
预发布版本必须写版本号
1.1.0-beta.1 这类预发布版本,CocoaPods 在不写版本号时不会选中,报 There are only pre-release versions available satisfying the following requirements。 写上精确版本号即可。
子模块带入的广告 SDK
不需要再单独引入穿山甲、优量汇的 SDK。 子模块会带入以下版本(均为真机验证过的版本):
| 子模块 | 带入的广告 SDK | 来源 |
|---|---|---|
AdMix/CSJ | Ads-CN/BUAdSDK 7.8.0.8 | CocoaPods 官方源 |
AdMix/GDT | GDTMobSDK 4.16.11 | CocoaPods 官方源 |
- 穿山甲只带入
BUAdSDK子模块。Ads-CN的默认子模块会额外拖进直播 SDK,平台不需要它 - 已有工程手工拖入过穿山甲 / 优量汇 framework 的,要先删掉这些文件和对应的链接设置, 否则会出现重复符号链接错误
- 宿主代码只应调用 AdMix 的对外 API,不要直接调用两家广告 SDK 的类
广告 SDK 的版本锁定
为什么要锁
适配器里的取价、竞价回传、各回调的时序,都是照某一个广告 SDK 版本的实测行为写的。 版本被换掉之后既不报错也不崩,典型表现是某个广告位就是不出广告 —— 端上日志正常、平台后台也正常,只有填充率悄悄掉下去。所以这件事被提到 pod install 时暴露。
冲突时的报错
两个子模块对广告 SDK 声明的是精确版本。工程里出现别的版本时 pod install 直接失败:
text
[!] CocoaPods could not find compatible versions for pod "GDTMobSDK":
In Podfile:
AdMix (= 1.0.0) was resolved to 1.0.0, which depends on
AdMix/GDT (= 1.0.0) was resolved to 1.0.0, which depends on
GDTMobSDK (= 4.16.11)
GDTMobSDK (= 4.16.10)报错末尾那句「required a higher minimum deployment target」不是真实原因
同一段输出的最后通常还有一句 Specs satisfying the ... dependency were found, but they required a higher minimum deployment target. 这是 CocoaPods 在约束合并后无解时的通用说法。两家广告 SDK 锁定版本声明的最低系统都是 iOS 11.0, 低于 AdMix 的 12.0,不存在部署目标问题。照这句去调 platform :ios 或 deployment target 解决不了, 真实原因是上面列出的两个版本对不上。
两个子模块声明的是精确版本(=),所以宿主工程引了比锁定版本更高或更低的版本都会冲突失败。 CocoaPods 的依赖声明没有附带说明文字的字段,报错里只有上面这段通用输出,看不到 AdMix 为什么要锁版本 —— 原因见上一节「为什么要锁」。
正确做法:把冲突那一行去掉。版本是被别的 pod 间接带进来的,Podfile.lock 的 DEPENDENCIES / PODS 两节能看出是谁。
确实需要升级广告 SDK 时联系平台。平台在新版本上跑完三种广告位的真机验证后发布新版 AdMix, 宿主只升 AdMix 的版本号。
运行时再核一次
手工集成能绕过 CocoaPods 的版本约束,所以 SDK 首次用到某家广告平台时会读取其 SDK 的 实际版本与锁定版本比对,不一致时打一条警告(只告警,不阻断,广告照常跑), 并随拉配置与埋点上报给平台:
text
[W] 适配器就绪: csj (ADN SDK 7.8.0.6) ⚠️ 版本与适配器锁定的 7.8.0.8 不一致 —— …版本一致时这一行没有 [W] 前缀。接入后先看一眼。
按需集成单家广告平台
SDK 不在代码里写死「支持哪几家」。每个适配器以 AdMixAdapter 为前缀的类自己声明身份, Core 启动时扫描一遍 App 里实际链接进来的类,引了谁就发现谁。由此:
- 只引
Core+CSJ的 App 里根本不存在优量汇的适配器,不是「跳过一家」,而是那一家不存在。 不会崩、不报错 - 拉配置时 SDK 会把实际发现的适配器列表报给平台,服务端据此把未集成的广告平台从下发的配置里摘掉。 日志里能看到
适配器自检: 发现 [csj]与拉取远端配置 … adapters=[csj]
链接参数 -ObjC
CocoaPods 集成时宿主工程自动获得 -ObjC,无需额外配置。
缺少 -ObjC 时一条广告都不会有
适配器只被 SDK 在运行时按类名查找,宿主代码里没有任何地方直接引用它。没有 -ObjC 时, 链接器会把适配器当成无用代码丢掉。构建完全正常,日志打 适配器自检: 一个都没有发现,所有广告位都没有广告。 手工集成,或宿主在 post_install 里改写过 OTHER_LDFLAGS 的工程,要核对这一项。
手工集成
无法使用 CocoaPods 的工程可以手工集成 xcframework(获取方式联系平台运营):
- 把
AdMixCore.xcframework与需要的AdMixAdapterCSJ.xcframework/AdMixAdapterGDT.xcframework加入工程,Embed 选 Do Not Embed(均为静态库) - 自行从穿山甲后台 / 优量汇开发者平台下载上表所列的同一版本广告 SDK 并按其文档集成
- Other Linker Flags 加
-ObjC - 把每个 xcframework 里的
PrivacyInfo.xcprivacy一并加入 App 包(隐私报告靠它汇总,见《合规与隐私》)
手工集成没有版本锁
两家广告 SDK 的版本只能人工对齐。装错版本不会在构建期报错, 只能靠启动日志里那行 适配器就绪: … 是不是带警告来发现。
模拟器架构
优量汇 SDK 没有 arm64 模拟器切片,其 podspec 会把宿主工程的模拟器构建限定为 x86_64。 Apple 芯片的 Mac 上模拟器构建因此经由 Rosetta 运行,属预期现象,真机构建不受影响。 只接穿山甲的工程不受这条限制。
网络安全配置
两家广告平台的部分素材通过明文 http 下发,系统的 App Transport Security(ATS)默认拦截这类请求 (NSURLErrorDomain -1022)。表现是广告位有填充、画面缺图或空白,而不是加载失败。 这是广告平台的要求,平台 SDK 自身的请求全部走 https。
真机对照实验(测试广告位实测):
| Info.plist 配置 | 结果 |
|---|---|
只开 NSAllowsArbitraryLoadsInWebContent | 仍被拦截。素材由广告 SDK 直接下载,不经过 WebView,这一档管不到 |
只为穿山甲素材域名 pglstatp-toutiao.com 配置例外 | 该域名放行,但同一批广告里还出现了广告主自有的素材域名(实测 images.pinduoduo.com),无法事先列全 |
NSAllowsArbitraryLoads | 不再拦截。两家官方 Demo 采用的也是这一项 |
推荐配置:
xml
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>只配域名例外时的表现
改为只给广告平台的素材域名配置 NSExceptionDomains 时,广告主自有域名下的 http 素材会加载失败, 表现是广告位里出现空白或半截素材,而不是不出广告。此时平台侧的填充、曝光数据一切正常, 从报表上看不出异常。
选择全局放开时,提交 App Store 审核需在审核备注中说明用途(加载第三方广告素材)。
URL Scheme 白名单
SDK 不要求宿主在 Info.plist 中声明任何 LSApplicationQueriesSchemes。
不要照抄广告平台 Demo 的白名单
穿山甲官方 Demo 的 Info.plist 声明了 34 条 scheme,其中大部分是 Demo 自身的分享与登录功能所需。 照抄会让宿主 App 在隐私问卷中多出一批需要逐条解释的查询行为。