SDK 运行时中的广告 SDK 无法访问发布商的视图层次结构。实际上,运行时中的 SDK 有自己的视图。SDK 无法使用与它在 SDK 运行时外部使用的相同 View API 来确定是否要向用户展示广告,因为广告视图不会附加到应用窗口。这包括了多个 Android View API,例如 getLocationOnScreen
、getLocationInWindow
或 getVisibility
,它们都不会返回预期值。
支持广告可见度衡量是 SDK 运行时的一项核心要求。此设计方案旨在实现对 Open Measurement 以及类似衡量服务的支持。本文讨论的解决方案可能也适用于 Attribution Reporting API。
功能
此设计旨在协助广告 SDK 或衡量合作伙伴计算以下可见度数据(名称是临时的,可能会发生变化):
viewport [Rect]
:表示设备屏幕或应用窗口几何形状,具体取决于平台的功能。uiContainerGeometry [Rect]
:正在渲染的SandboxedSdkView
的几何形状。alpha [float]
:正在渲染的SandboxedSdkView
的不透明度。onScreenGeometry [Rect]
:不被父视图裁剪的uiContainerGeometry
的子集,取决于所包含的viewport
。occludedGeometry [Rect]
:onScreenGeometry
中被应用层次结构内的任何视图遮挡的部分。每个遮挡部分包含一个Rect
,分别对应于与SandboxedSdkView onScreenGeometry
相交的 0 个、1 个或多个应用视图
要求
uiContainerGeometry
、onScreenGeometry
和occludedGeometry
的值以viewport
坐标空间中的坐标表示。- 以最短延迟时间报告可见度更改。
- 可见度在广告视图的整个生命周期内(从首次展示到最后一次展示)都是可衡量的。
设计方案
此方案的基础是使用客户端和提供方界面库进行界面呈现的方式。我们将扩展界面库,以允许 SDK 注册一个或多个界面会话的观察器。每当检测到对功能部分中的数据类型做出修改的相关事件时,观察器就会收到可见度信息。SDK 运行时中的衡量 SDK(OMID 和 MRAID 实现)可将此观察器附加到界面会话,以便直接将此信息发送给这些 SDK。衡量合作伙伴可将从界面库获取的信息与已有内容的数据相结合(例如,使用注入到广告素材中的衡量脚本时可用的数据),从而生成 JavaScript 可见度事件。
客户端库通过事件监听器(例如 ViewTreeObserver
)监听广告界面中的更改。每当客户端库确定广告界面发生的更改可能会影响可见度衡量时,客户端库就会检查上次通知是在何时发送给观察器的。如果上次更新超出了允许的延迟时间(可由 SDK 配置,移动设备上的最短延迟时间上限为 200 毫秒),系统便会创建一个新的 AdContainerInfo
对象,并向观察器派发一条通知。与目前 Android 上由大多数 OMID 实现进行轮询的做法相比,这种基于事件的模型有助于改善系统运行状况。
API
以下内容将添加到 privacysandbox.ui.core 库:
SessionObserver
:通常由衡量 SDK 实现,附加到 SDK 通过 privacysandbox.ui 返回的会话。此接口还允许衡量 SDK 选择使用特定类别的可见度信号。另一方面,此接口可让界面客户端库只收集观察器感兴趣的信号,这有助于改善系统的总体运行状况。registerObserver()
:添加到Session
类后,此方法允许任何有权访问会话的 SDK 注册观察器。如果在界面会话已打开的状态下注册观察器,系统会立即将缓存的AdContainerInfo
发送给这些 SDK。如果在会话打开之前注册观察器,系统会在会话打开时将AdContainerInfo
发送给这些 SDK。AdContainerInfo
:一个带有 getter 的类,可让观察器获取上述功能部分中所列数据类型的只读广告容器信息。来自这些 getter 的返回值将尽可能与对View
及其子类调用现有 getter 后收到的 Parcelable 返回值对应。如果广告容器是使用 Jetpack Compose 创建的,这会公开容器的语义属性。此类可用于计算与可见度相关的 MRAID 和 OMID 事件。SessionObserverotifyAdContainerChanged()
:用于在可见度发生变化时通知观察器。它会传递一个AdContainerInfo
对象。每当检测到影响“功能”部分中所列数据类型的事件时,系统就会调用此方法。注意:除了对会话调用方法之外,系统也可能会调用此方法。例如,系统会调用Session.notifyResized()
以请求 SDK 调整广告的大小,当这种情况发生时,系统也会调用SessionObserver.notifyAdContainerChanged()
。SessionObserverotifySessionClosed()
:通知观察器会话已关闭。
未来的增强功能
如果应用遭到破解,应用进程中运行的任何代码(包括 privacysandbox.ui.client 库中的代码)都可以被修改。因此,应用进程中运行的任何信号收集逻辑都很容易被应用代码篡改。这同样适用于在 Privacy Sandbox 可用之前部署并在应用进程中运行的 SDK 代码。所以,由界面库收集信号并不会使安全状况变差。
此外,SDK 运行时中的代码可以使用一个名为 setTrustedPresentationCallback
的平台 API,该 API 可以通过框架更好地保证广告界面呈现效果。setTrustedPresentationCallback
在 Surface 级运行,可通过指定最低呈现阈值(例如可见像素的百分比、屏幕停留时间或比例)来帮助对包含广告界面的 Surface 进行断言。您可以将这些数据与界面客户端库提供的可见度数据(如上文所述)进行对比检查。由于框架提供的数据更加可靠,因此,对于来自界面库的任何事件,如果其数据与框架提供的数据不一致,该事件就可能被舍弃。例如,如果调用了提供给 setTrustedPresentationCallback
的监听器,并且通知屏幕上将不显示任何广告界面像素,而客户端界面库在屏幕上显示了非零数量的像素,那么来自后者的数据就可能被舍弃。
开放性问题
- 您对哪些可见度信号感兴趣,但本说明文章中却未提及?
- 当前方案是:在界面有相关更改的前提下,可见度的更新频率不低于每 200 毫秒一次。您能接受这个频率吗?如果不能接受,您希望采用什么频率?
- 当界面库提供的数据与
setTrustedPresentationCallback
数据不匹配时,您是希望自行分析来自setTrustedPresentationCallback
的信息,还是希望提供方界面库舍弃客户端界面库提供的数据? - 您如何使用可见度信号?请通过回答这些问题来提交反馈意见,帮助我们了解您的用例。