adattributionkit

adattributionkit

热门

使用 AdAttributionKit 在保护用户隐私的前提下测量广告效果。适用于注册广告曝光(impression)、处理归因回传(postback)、更新转化值(conversion value)、实现二次互动(re-engagement)归因、配置媒体端(publisher)或广告主端(advertiser)应用,以及使用 AdAttributionKit 替代 SKAdNetwork 进行广告测量。

967Star
49Fork
更新于 2026/7/31
SKILL.md
只读
名称
adattributionkit
描述

使用 AdAttributionKit 在保护用户隐私的前提下测量广告效果。适用于注册广告曝光(impression)、处理归因回传(postback)、更新转化值(conversion value)、实现二次互动(re-engagement)归因、配置媒体端(publisher)或广告主端(advertiser)应用,以及使用 AdAttributionKit 替代 SKAdNetwork 进行广告测量。

AdAttributionKit

面向 iOS 17.4+ 的隐私保护型广告归因框架。AdAttributionKit 允许广告网络在不暴露用户级数据的前提下测量转化(安装与二次互动)。它同时支持 App Store 和第三方应用市场(alternative marketplaces),并能与 SKAdNetwork 保持互操作。

归因流程中存在三种角色:广告网络(Ad network,负责签署曝光、接收回传)、媒体端应用(Publisher app,负责展示广告)和广告主端应用(Advertised app,被推广的目标应用)。

目录

概览与隐私模型

AdAttributionKit 通过以下机制保护用户隐私:

  • 人群匿名分级(Crowd anonymity tiers) —— 设备根据与广告相关联的人群规模来限制回传数据的粒度,分为 Tier 0(极简数据)到 Tier 3(最丰富数据,包含媒体端 ID 和国家/地区代码)。
  • 延时归因回传(Time-delayed postbacks) —— 回传会在转化窗口关闭后的 24–48 小时发送(第一个窗口),或 24–144 小时发送(第二/三个窗口)。
  • 无用户级标识符 —— 回传仅包含聚合后的来源标识符(source identifiers)和转化值,不包含任何设备 ID 或用户 ID。
  • 层级化来源标识符 —— 2 位、3 位或 4 位的来源 ID,具体返回几位取决于当前的人群匿名分级。

在迁移和互操作性评估中,需明确说明:系统会将 AdAttributionKit 和 SKAdNetwork 的曝光放在一起综合评估,每次转化仅有一个曝光胜出;点击归因(click-through)优先于展示归因(view-through);在点击归因同分时,更近发生的点击胜出,最后才会倒退回选最近一次展示归因。

媒体端应用配置

媒体端应用用于展示已注册广告网络的广告。需将各个广告网络的 ID 添加到应用的 Info.plist 中,以便其曝光具备安装验证资格。

添加广告网络标识符

<key>AdNetworkIdentifiers</key>
<array>
    <string>example123.adattributionkit</string>
    <string>another456.adattributionkit</string>
</array>

广告网络 ID 必须全部小写。系统同样支持 SKAdNetwork ID(以 .skadnetwork 结尾)——两个框架共享这些 ID。

展示 UIEventAttributionView

对于自定义渲染的点击类广告,需要在每个可点击的广告/控件上方覆盖一个 UIEventAttributionView。它必须完整覆盖点击区域,并保持在可能拦截触摸事件的其他视图之上,以确保 handleTap() 能够成功调用。

import UIKit

let attributionView = UIEventAttributionView()
attributionView.frame = adContentView.bounds
attributionView.isUserInteractionEnabled = true
adContentView.addSubview(attributionView)

广告主端应用配置

广告主端应用是指用户在看到广告后安装或重新打开的应用。它必须至少调用一次转化值更新,以开启回传转化窗口。

开启接收胜出回传副本

在顶级 AdAttributionKit Info.plist 字典下添加 AttributionCopyEndpoint,以便设备将胜出回传的副本发送到你的服务器:

<key>AdAttributionKit</key>
<dict>
    <key>AttributionCopyEndpoint</key>
    <string>https://example.com</string>
</dict>

系统会从 URL 中的可注册域名衍生出标准端点路径(忽略子域名):

https://example.com/.well-known/appattribution/report-attribution/

请配置服务器在该路径下接收 HTTPS POST 请求。域名必须配备有效的 SSL 证书。

开启接收二次互动回传副本

在同一个 AdAttributionKit 字典中添加第二个键,以同时接收胜出二次互动回传的副本:

<key>AdAttributionKit</key>
<dict>
    <key>AttributionCopyEndpoint</key>
    <string>https://example.com</string>
    <key>OptInForReengagementPostbackCopies</key>
    <true/>
</dict>

首次启动时更新转化值

应用首次启动后,尽早调用转化值更新以开启转化窗口:

import AdAttributionKit

func applicationDidFinishLaunching() async {
    do {
        try await Postback.updateConversionValue(0, lockPostback: false)
    } catch {
        print("Failed to set initial conversion value: \(error)")
    }
}

广告曝光

广告网络使用 JWS(JSON Web Signature)生成已签名的曝光数据。媒体端应用使用 AppImpression 来注册和处理这些曝光。

根据 JWS 创建曝光

import AdAttributionKit

let impression = try await AppImpression(compactJWS: signedJWSString)

JWS 包含广告网络 ID、被推广项目 ID、媒体端项目 ID、来源标识符、时间戳以及可选的二次互动资格标志。详见 references/adattributionkit-patterns.md 了解 JWS 生成细节。

检查设备支持情况

guard AppImpression.isSupported else {
    // 降级使用其他广告展示方式
    return
}

展示归因曝光

当广告内容展示完毕并被关闭时,记录一次展示曝光:

func handleAdViewed(impression: AppImpression) async {
    do {
        try await impression.handleView()
    } catch {
        print("Failed to record view-through impression: \(error)")
    }
}

对于长时间展示的广告,使用 beginView()endView() 来追踪展示时长:

try await impression.beginView()
// ... 广告保持可见 ...
try await impression.endView()

点击归因曝光

用户点击广告后,需在创建 AppImpression 的 15 分钟内调用 handleTap();否则需要请求新的曝光对象。若未安装广告主端应用,系统会打开其 App Store 或应用市场页面;若已安装,系统会直接拉起应用。

func handleAdTapped(impression: AppImpression) async {
    do {
        try await impression.handleTap()
    } catch {
        print("Failed to record click-through impression: \(error)")
    }
}

广告上方必须覆盖 UIEventAttributionViewhandleTap() 才能成功执行。

StoreKit 渲染的广告

将曝光对象传递给 StoreKit overlay 或商品页控制器 API。StoreKit 会在广告展示 2 秒后自动记录展示归因曝光,并在点击时自动记录点击归因曝光。

import StoreKit

let config = SKOverlay.AppConfiguration(appIdentifier: "1234567890",
                                         position: .bottom)
config.appImpression = impression

归因回传

归因回传是指在发生转化事件后,由设备发送给广告网络(以及可选的广告主应用开发者)的归因报告。

转化窗口

胜出的归因可能会跨越多个转化窗口生成多条回传;较低的数据分级和未胜出的归因披露的数据较少。有关最新的窗口与延迟矩阵,请参阅 references/adattributionkit-patterns.md

事件时间窗口

归因资格窗口与转化/回传窗口是不同的概念。请结合当前官方文档与参考资料配置并校验展示归因、点击归因、安装更新及二次互动的限制;切勿混淆这两个概念。

提前锁定转化值

在窗口结束前锁定回传以固定转化值,可以更早接收到回传:

try await Postback.updateConversionValue(
    42,
    coarseConversionValue: .high,
    lockPostback: true
)

锁定之后,系统将忽略该转化窗口内的后续更新。

各分级对应的回传数据

数据披露粒度随系统分配的数据分级提升而增加。代码和数据分析逻辑必须能够容忍缺失的来源位数、精细/粗粒度转化值、媒体端项目 ID 以及国家/地区代码。详细的分级矩阵见参考文档。

转化值

精细转化值

精细值为 0...63(6 位)的整数。它仅在第一个回传且处于 Tier 2 或更高分级时可用:

try await Postback.updateConversionValue(
    35,
    coarseConversionValue: .medium,
    lockPostback: false
)

粗粒度转化值

针对较低分级以及第二/第三个回传,分为三个等级:

// CoarseConversionValue 可选值:.low, .medium, .high
try await Postback.updateConversionValue(
    10,
    coarseConversionValue: .high,
    lockPostback: false
)

按转化类型更新(iOS 18+)

可以分别更新安装(install)与二次互动(re-engagement)回传的转化值。在服务端 JSON 中,使用带连字符的 "conversion-type": "re-engagement";而在 Swift API 中,使用不带连字符的 .reengagement

let installUpdate = PostbackUpdate(
    fineConversionValue: 20,
    lockPostback: false,
    conversionTypes: [.install]
)
try await Postback.updateConversionValue(installUpdate)

let reengagementUpdate = PostbackUpdate(
    fineConversionValue: 12,
    lockPostback: false,
    conversionTypes: [.reengagement]
)
try await Postback.updateConversionValue(reengagementUpdate)

转化标签(iOS 18.4+)

当存在重叠的转化窗口时,使用转化标签有选择地更新特定回传:

let update = PostbackUpdate(
    fineConversionValue: 15,
    lockPostback: false,
    conversionTag: savedConversionTag,
    conversionTypes: [.reengagement]
)
try await Postback.updateConversionValue(update)

系统会通过二次互动 URL 的 AdAttributionKitReengagementOpen 查询参数传递转化标签。

二次互动

二次互动用于追踪已安装广告主端应用的用户,通过点击广告重新返回应用的行为。

将曝光标记为具备二次互动资格

生成曝光数据时,将 JWS Payload 中的 eligible-for-re-engagement 设置为 true

使用 URL 处理二次互动点击

传递一个由系统在广告主端应用中打开的通用链接(Universal Link):

let reengagementURL = URL(string: "https://example.com/promo/summer")!
try await impression.handleTap(reengagementURL: reengagementURL)

系统会自动追加 AdAttributionKitReengagementOpen 作为查询参数。广告主端应用可通过检查此参数来识别由 AdAttributionKit 触发的打开行为:

func handleUniversalLink(_ url: URL) {
    let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
    let isReengagement = components?.queryItems?.contains(where: {
        $0.name == Postback.reengagementOpenURLParameter
    }) ?? false

    if isReengagement {
        // 本次打开是由 AdAttributionKit 二次互动广告触发的
    }
}

二次互动限制

  • 仅点击互动(Click-through)会生成二次互动回传,展示互动(View-through)不会。
  • 设备会对每个应用设置每月上限,对每台设备设置每年上限。
  • 无论系统最终是否生成回传,URL 上始终会附带 AdAttributionKitReengagementOpen 参数。

常见错误

常见错误 修复方案
首次启动时从未更新转化值 在预期的窗口超时前,调用标准的首次启动更新。
广告网络 ID 包含大写字符 严格使用小写的网络标识符。
handleTap() 使用了过期的曝光对象,或未在当前归因视图的点击中触发 UIEventAttributionView 覆盖广告区域,保持曝光对象最新,并在验证过的点击流程中进行调用。
点击错误...

<!-- 因翻译批次截断;正文后半部分见源文件 -->