Swift Markdown Kit · DOCS

点击交互

点击交互

读者点链接、点图片、点复制、点重试时会发生什么,以及怎么把其中任意一项接管 过来。

划线规则

SDK 只有一条判断标准:这个动作是否离开渲染区域?

交互谁来做能改吗
复制(代码块、消息)SDK,始终行为不能改,是否显示可以。
推理折叠SDK,始终文案和默认状态可以改。
任务勾选SDK,始终——
链接默认 SDK可以,改一行。
图片默认 SDK可以,改一行。
重试、编辑始终是你SDK 无法重新发起你的请求。
自定义语法点击始终是你——

复制和折叠不需要 App 提供任何信息,把它们交给你只是徒增工作量。而打开链接或 图片会离开渲染区域,那里你的 App 有理由拥有最终决定权。

链接与图片

什么都不做,两者就能用:链接在应用内 SFSafariViewController 打开,图片在 全屏预览器打开,支持双指缩放、双击放大、下拉关闭。

想接管其中一项:

var options = MarkdownChatRenderOptions()
options.interaction.images = .handledByHost   // 链接仍由 SDK 处理
MarkdownChatRenderView(messages: messages, options: options) { event in
    guard case .action(let event) = event,
          case .imageTapped(let url) = event.action, let url else { return }
    presentMyOwnViewer(url)
}

每一项各有三种策略:

策略行为你收到什么
.automatic(默认)SDK 在应用内打开。didOpenLink / didPresentImage —— 通知。
.handledByHost什么都不做。linkTapped / imageTapped —— 不处理就没有反应。
.disabled什么都不做,且元素不再显示为可点击。什么都不发。

options.interaction = .manual 可以一次把两项都设成 .handledByHost

通知不是否决

两类事件被刻意区分开:

  • 请求 —— linkTappedimageTappedextensionTapped。SDK 什么都没做, 你不处理就没有任何反应。
  • 通知 —— didOpenLinkdidPresentImagecodeCopiedreasoningToggled。SDK 已经做完了,你再处理一次就会打开两次。

没有任何回调可以取消一个自动行为。想控制它,就改策略 —— 策略就是为此存在的。

链接安全

渲染的内容是模型输出,而模型是可以被诱导吐出 javascript:file://、或者 指向你自己 App 的深链的。因此,不在白名单内的 scheme 既不会被打开,也不会交给你

options.interaction.allowedLinkSchemes   // 默认 ["http", "https", "mailto"]
options.interaction.allowedLinkSchemes.insert("myapp")

其余一律以 linkBlocked(url:scheme:) 上报,方便你记录。这条规则在所有策略下 都生效,包括 .handledByHost —— 接管了链接处理,也不构成把 javascript: 递给你的理由。

两个渲染器还会拒绝任何可能替换掉渲染页面的导航。链接点击在页面内就被取消并走 bridge,所以真正抵达导航层的跳转,按定义就是异常。

复制

复制从不外包:SDK 写入剪贴板,然后告诉你结果。可配置的是这个入口是否存在 —— 有些 App 出于数据防泄漏要求必须能移除它:

options.interaction.allowsCodeCopy = false          // 代码块不显示复制按钮
options.messageActions.assistantActions = []        // 消息下方不显示工具条
MarkdownChatRenderView(messages: messages) { event in
    guard case .action(let event) = event else { return }
    if case .codeCopied = event.action { showToast("已复制") }
    if case .codeCopyFailed(_, _, let error) = event.action { showToast(error.message) }
}

重试与编辑

SDK 无法重新发起请求,也无法写进不属于它的输入框,所以这两个按钮只有你列出时 才会出现 —— 而列出它们,就是你承诺会处理 messageAction。见 流式与会话

自定义语法

点击已注册的行内扩展 —— @某人[[wikilink]] —— 会以 extensionTapped(name:action:value:) 上报,始终由你来路由。见 主题与语法