Documentation Index
Fetch the complete documentation index at: https://docs.kontext.so/llms.txt
Use this file to discover all available pages before exploring further.
处理 no-fill
订阅 AdEvent.NoFill 即可知道何时没有广告返回(地域限制、频次封顶等)。skipCode 字段说明了原因。
onEvent = { event ->
if (event is AdEvent.NoFill) {
android.util.Log.d("kontext", "no fill: ${event.skipCode}")
}
}
生命周期管理
对话结束或页面关闭时,请始终调用 session.destroy()(或其别名 session.close())。它会取消正在进行的预加载、销毁所有挂载的广告、结束 OMID 会话并释放 WebView 资源。幂等。
在 Compose 中,挂在页面级的 DisposableEffect 上:
DisposableEffect(session) {
onDispose { session.close() }
}
在 ViewModel 中:
override fun onCleared() {
session.destroy()
super.onCleared()
}
动态更新会话选项
会话选项的一部分字段可以在不重建 session 的情况下动态更新。更新在下一次 /preload 时被读取,因此在下一条用户消息后生效。
import so.kontext.ads.model.MutablePublisherOptions
session.updateOptions(MutablePublisherOptions(variantId = "new-variant"))
可动态更新的字段:variantId、regulatory、userEmail、advertisingId。非 null 字段覆盖原值;null 字段保持不变。如果要清空某个字段,请重建会话。
publisherToken、userId、conversationId、enabledPlacementCodes 和 character 不可 动态更新。中途修改会导致 /init 注册与后续请求脱节,或让累积的消息历史指向错误的角色。这些场景请重建会话。
中途更新同意状态
当用户在你的 CMP 中更新了同意状态,调用:
import so.kontext.ads.model.Regulatory
session.updateOptions(MutablePublisherOptions(
regulatory = Regulatory(gdpr = 1, gdprConsent = "<new-TCF-string>"),
))
下一次预加载会带上新值——无需重建 session。
切换 character
character 不能动态更新——已累积的消息历史属于原本的角色;中途切换会导致后续消息以错误的人物画像被定向。
切换角色请销毁当前会话并新建:
session.destroy()
session = KontextAds.createSession(
context = applicationContext,
options = SessionOptions(
publisherToken = "<your-publisher-token>",
userId = "user-1234",
conversationId = "conv-new",
character = newCharacter,
),
)
publisherToken、userId、conversationId、enabledPlacementCodes 同理——任何一个变化都请重建会话。
载入历史消息(会话恢复)
从你的后端恢复会话时,按顺序对每条历史消息调用一次 addMessage(...)。预加载本身带有防抖,因此连续的 add 调用会合并为对最近一条用户消息的单次预加载——不会因为恢复了 N 条消息就发出 N 次预加载。
for (historical in loadedFromBackend) {
session.addMessage(
Message(
id = historical.id,
role = historical.role,
content = historical.content,
),
)
}
把每条消息都喂入,用 trackOnly 控制是否展示广告
无论是否打算展示广告(付费用户、免广告地区、或每 N 条消息才展示一次广告等),都请把消息全部喂入会话。跳过 addMessage(...) 调用会破坏服务端用于定向的对话上下文。完整模式见 Pacing。
import so.kontext.ads.model.AddMessageOptions
val shouldShowAd = userMessageCount % 5 == 0
session.addMessage(
Message(id = msg.id, role = Role.USER, content = msg.content),
AddMessageOptions(trackOnly = !shouldShowAd),
)
当 trackOnly = true 时,预加载仍会发送(服务端保留完整分析数据),但不会为该条消息触发 AdEvent.Filled,session.createAd(...) 也不会拿到可填充的广告。
向 InlineAd composable 传入一个发布方自定义的主题字符串;它会进入 iframe 的 update-iframe 负载,供广告创意读取。
InlineAd(
messageId = msg.id,
session = session,
theme = if (isSystemInDarkTheme()) "dark" else "light",
)
主题是 Ad 身份键的一部分——同一个 messageId 下切换主题会让 iframe 以新的主题重新加载。
View 互操作(非 Compose)
非 Compose 项目请使用 InlineAdView(FrameLayout 子类)。像普通 view 一样实例化或 inflate,然后调用 bind(messageId, session):
import so.kontext.ads.ui.InlineAdView
val adView = InlineAdView(context)
adView.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
adView.onHeightChange = { newHeight ->
// 如果你在 RecyclerView 行里,请重新触发行布局
requestRowLayout()
}
adView.bind(messageId = assistantMessageId, session = session)
container.addView(adView)
InlineAdView 遵循与 composable 相同的生命周期规则——页面销毁时调用 session.destroy();view 内的 WebView 由会话的池来回收。