mcpField
A
adattributionkit

adattributionkit

github.com/dpearson2699营销与增长1.2k3.1k 次安装13 周前更新
代码仓库

关于 adattributionkit

AdAttributionKit 的开发参考技能,面向实现 iOS 广告归因的开发者,涵盖隐私保护归因、转化回传及再互动流程,并说明与 SKAdNetwork 的互操作。

主要功能

  1. 01隐私保护归因机制
  2. 02签名广告展示与点击
  3. 03转化值和回传管理
  4. 04再互动归因流程
  5. 05实现检查清单

适用场景

  1. 01配置发布方和广告应用
  2. 02记录广告展示及点击
  3. 03设置转化值与归因窗口
  4. 04验证回传端点和数据处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill adattributionkit

安装后在 Claude Code 中输入/adattributionkit确认已加载。

附带文件evals/evals.jsonreferences/adattributionkit-patterns.md

详细介绍

AdAttributionKit

为 iOS 17.4+ 提供保护隐私的广告归因。AdAttributionKit 让广告网络能够衡量转化(安装和重新互动),同时不暴露用户级数据。它支持 App Store 和其他市场,并可与 SKAdNetwork 互操作。

归因流程中有三个角色:广告网络(签署展示并接收回传)、发布者应用(展示广告)和 广告应用(被推广的应用)。

目录

概览和隐私模型

AdAttributionKit 通过多种机制保护用户隐私:

  • 群体匿名级别 —— 设备根据与广告相关联的群体规模限制回传数据的粒度,级别从 0 级(数据最少)到 3 级(数据最多,包括发布者 ID 和国家/地区代码)。
  • 延迟回传 —— 在转化窗口关闭后 24-48 小时(第一个窗口)或 24-144 小时(第二个/第三个窗口)发送回传。
  • 不包含用户级标识符 —— 回传包含聚合的来源标识符和转化值,而不包含设备或用户 ID。
  • 分层来源标识符 —— 来源 ID 为 2、3 或 4 位数,返回的位数取决于群体匿名级别。

在迁移和互操作性审核中,请明确说明:系统会同时评估 AdAttributionKit 和 SKAdNetwork 展示;每次转化只有一个展示会胜出;点击归因优先于浏览归因;在点击归因展示中,较新的展示优先;如果无法据此决出,则采用最新的浏览归因展示。

发布者应用设置

发布者应用会展示来自已注册广告网络的广告。将每个广告网络的 ID 添加到应用的 Info.plist 中,使其展示符合安装验证条件。

添加广告网络标识符
<key>AdNetworkIdentifiers</key>
<array>
    <string>example123.adattributionkit</string>
    <string>another456.adattributionkit</string>
</array>

广告网络 ID 必须为小写。也接受以 .skadnetwork 结尾的 SKAdNetwork ID——这些框架共用 ID。

显示 UIEventAttributionView

对于点击归因的自定义渲染广告,在每个可点按的广告/控件上放置一个 UIEventAttributionView。它必须覆盖可点按区域,并位于可能拦截触摸事件的视图上方,以确保 handleTap() 能成功执行。

import UIKit

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

广告应用设置

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

选择接收胜出回传的副本

在 Info.plist 顶层的 AdAttributionKit 字典下添加 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、来源标识符、时间戳,以及可选的重新互动资格标记。有关 JWS 生成详情,请参阅 references/adattributionkit-patterns.md。

检查设备是否受支持
guard AppImpression.isSupported else {
    // Fall back to alternative ad display
    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()
// ... ad remains visible ...
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)")
    }
}

UIEventAttributionView 必须覆盖广告,handleTap() 才能成功。

StoreKit 渲染的广告

将展示传递给 StoreKit 覆盖层或商品视图控制器 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 cases: .low, .medium, .high
try await Postback.updateConversionValue(
    10,
    coarseConversionValue: .high,
    lockPostback: false
)
按转化类型更新(iOS 18+)

为安装和重新互动回传分别设置转化值。在服务器 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 负载中将 eligible-for-re-engagement 设为 true。

使用 URL 处理重新互动点按

传入一个由系统在广告推广应用中打开的通用链接:

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 opened this app via a re-engagement ad
    }
}
再互动限制
  • 只有点击互动会生成再互动回传(浏览互动不会)。
  • 设备会强制执行每月每个应用和每年每台设备的再互动限制。
  • 即使系统不创建回传,URL 中也始终会包含 AdAttributionKitReengagementOpen 参数。

常见错误

错误修正方法
首次启动从未更新转化值在预期时间窗口结束前,调用规范的首次启动更新。
广告网络 ID 包含大写字符使用完全一致的小写网络标识符。
handleTap() 使用过期的展示,或缺少当前归因视图点击使用 UIEventAttributionView 覆盖广告,确保展示仍然有效,并在经过验证的点击流程中调用。
忽略点击错误明确处理展示过期和缺少视图的情况。
回传端点延迟响应或未返回响应接收请求,持久化或排队处理,并及时返回预期的成功响应。

审查清单

  • 发布者应用在 AdNetworkIdentifiers 中包含所有广告网络 ID (小写)
  • 广告网络 ID 与发布者应用的 Info.plist 和 JWS kid 中的值一致
  • 每个可点击的点击广告/控件上方都覆盖有 UIEventAttributionView
  • 调用 handleTap() 时,点击产生的 AppImpression 不超过 15 分钟
  • 推广应用在首次启动时调用 updateConversionValue
  • 知名路径上的服务器端点接受带有效 SSL 的 HTTPS POST 请求
  • 回传验证针对相应环境使用正确的 Apple 公钥
  • 根据 postback-identifier 过滤重复回传
  • 服务器对回传请求返回 HTTP 200
  • 再互动 URL 是推广应用已注册的通用链接
  • 转化值策略考虑全部三个转化窗口
  • 尝试使用展示 API 前,检查 AppImpression.isSupported

参考资料

评论

支持 Markdown