SnippetIntent PRO

需要 Scripting PRO

SnippetIntent 是一种特殊类型的 AppIntent,可在 Shortcuts 中生成原生的 Snippet UI 卡片。它适用于:

  • 多步骤表单式交互
  • 从 Shortcuts 中获取用户输入
  • 键值选择、确认、展示结果等轻量级交互
  • 在 Shortcuts 工作流中内嵌 UI 组件

SnippetIntent 特点如下:

  1. 在 Scripting 中必须通过 AppIntentManager.register 注册
  2. protocol 必须为 AppIntentProtocol.SnippetIntent
  3. perform() 必须返回一个 VirtualNode(TSX UI)
  4. 在脚本中必须以 Intent.snippetIntent() 封装后返回
  5. Shortcuts 必须使用「Show Snippet Intent」动作才能显示 Snippet UI

系统要求

SnippetIntent 只能在 iOS 26 及以上系统运行。

在 iOS 26 以下环境:

  • 无法调用 Intent.snippetIntent
  • 无法使用 Intent.requestConfirmation
  • Shortcuts 中不存在「Show Snippet Intent」动作
  • SnippetIntent 类型的 AppIntent 不会被 Shortcuts 正常识别

注册 SnippetIntent(app_intents.tsx)

app_intents.tsx 中声明 SnippetIntent:

1export const PickColorIntent = AppIntentManager.register<void>({
2  name: "PickColorIntent",
3  protocol: AppIntentProtocol.SnippetIntent,
4  perform: async () => {
5    return <PickColorView />
6  }
7})

再例如:

1export const ShowResultIntent = AppIntentManager.register({
2  name: "ShowResultIntent",
3  protocol: AppIntentProtocol.SnippetIntent,
4  perform: async ({ content }: { content: string }) => {
5    return <ResultView content={content} />
6  }
7})

要求:

  • protocol 必须为 AppIntentProtocol.SnippetIntent
  • perform() 必须返回 VirtualNode
  • 与普通 AppIntent 区别在于返回的是 UI,而非数据

SnippetIntent 返回值封装:Intent.snippetIntent

SnippetIntent 不能直接作为 JS 返回值,必须通过 Intent.snippetIntent() 包装成 IntentSnippetIntentValue

1const snippetValue = Intent.snippetIntent({
2  value: Intent.text("Some value returning for Shortcuts"),
3  snippetIntent: ShowResultIntent({
4    content: "Example Text"
5  })
6})
7
8Script.exit(snippetValue)

类型定义

1type SnippetIntentValue = {
2  value?: IntentAttributedTextValue | IntentFileURLValue | IntentJsonValue | IntentTextValue | IntentURLValue | IntentFileValue | null
3  snippetIntent: AppIntent<any, VirtualNode, AppIntentProtocol.SnippetIntent>
4}
5
6declare class IntentSnippetIntentValue extends IntentValue<
7  'SnippetIntent',
8  SnippetIntentValue
9> {
10  value: SnippetIntentValue
11  type: 'SnippetIntent'
12}

封装的返回值可被 Shortcuts 的「Show Snippet Intent」动作识别并展示 UI。


Snippet 确认界面:Intent.requestConfirmation

SnippetIntent 支持在执行逻辑中先请求用户确认某个操作。此能力同样基于 iOS 26。

1Intent.requestConfirmation(
2  actionName: ConfirmationActionName,
3  intent: AppIntent<any, VirtualNode, AppIntentProtocol.SnippetIntent>,
4  options?: {
5    dialog?: Dialog;
6    showDialogAsPrompt?: boolean;
7  }
8): Promise<void>

ConfirmationActionName

这些名称会影响 Shortcuts UI 中呈现的文案,例如 “Set …”、“Add …”、“Toggle …” 等。

示例值:

"add" | "addData" | "book" | "buy" | "call" | "checkIn" | "continue" | "create" | "do" | "download" | "filter" | "find" | "get" | "go" | "log" | "open" | "order" | "pay" | "play" | "playSound" | "post" | "request" | "run" | "search" | "send" | "set" | "share" | "start" | "startNavigation" | "toggle" | "turnOff" | "turnOn" | "view"

示例

1await Intent.requestConfirmation(
2  "set",
3  PickColorIntent()
4)

效果:

  • Shortcuts 弹出 PickColorIntent 对应的 Snippet UI
  • 用户点击确认后 Promise resolve
  • 用户取消时脚本执行终止

Shortcuts 的「Show Snippet Intent」动作(iOS 26+)

Shortcuts 在 iOS 26 新增动作:

Show Snippet Intent

用于展示 SnippetIntent 返回的 Snippet UI。

与其他动作对比

Shortcuts 动作 显示界面 支持 SnippetIntent 场景
Run Script 无 UI 纯数据处理
Run Script in App Scripting App UI(前台) 大型 UI、文件选择等
Show Snippet Intent(iOS 26+) Snippet 卡片 UI SnippetIntent 场景

使用方式:

  1. 在 Shortcuts 中添加「Show Snippet Intent」
  2. 选择脚本项目(需包含 intent.tsx)
  3. 脚本返回 Intent.snippetIntent(...)
  4. Shortcuts 显示 Snippet UI

IntentMemoryStorage — 跨 AppIntent 状态共享

1. 为什么需要 IntentMemoryStorage

由于系统行为,每次 Intent 执行后:

  • AppIntent 的 perform() 执行完毕后立即销毁上下文
  • intent.tsx 执行完并调用 Script.exit() 后脚本上下文也会完全释放

因此无法依赖 JS 变量在多个 Intent 之间保持状态。

例如:

  • PickColorIntent(选择颜色)
  • SetColorIntent(设置颜色)
  • ShowResultIntent(展示颜色结果)

在这些 Intent 之间共享状态必须依赖持久化存储。

2. IntentMemoryStorage 提供轻量级、跨 Intent 的共享存储

API 定义:

1namespace IntentMemoryStorage {
2  function get<T>(key: string): T | null
3  function set(key: string, value: any): void
4  function remove(key: string): void
5  function contains(key: string): boolean
6  function clear(): void
7  function keys(): string[]
8}

用途:

  • 存储小量状态,例如当前颜色、当前步骤、临时选项
  • 在多个 AppIntent 之间共享数据
  • 生命周期跨 Intent 调用,但随脚本生命周期管理

示例:存储用户颜色选择

1IntentMemoryStorage.set("color", "systemBlue")
2
3const color = IntentMemoryStorage.get<Color>("color")

建议

  • 不要存储大型数据(如大图像、长文本)

  • 大型数据请使用:

    • Storage(持久键值存储)
    • FileManager 写入 appGroupDocumentsDirectory

IntentMemoryStorage 适合作为临时状态共享,不适合当作数据库使用。


完整示例(iOS 26+)

app_intents.tsx

1export const SetColorIntent = AppIntentManager.register({
2  name: "SetColorIntent",
3  protocol: AppIntentProtocol.AppIntent,
4  perform: async (color: Color) => {
5    IntentMemoryStorage.set("color", color)
6  }
7})
8
9export const PickColorIntent = AppIntentManager.register<void>({
10  name: "PickColorIntent",
11  protocol: AppIntentProtocol.SnippetIntent,
12  perform: async () => {
13    return <PickColorView />
14  }
15})
16
17export const ShowResultIntent = AppIntentManager.register({
18  name: "ShowResultIntent",
19  protocol: AppIntentProtocol.SnippetIntent,
20  perform: async ({ content }: { content: string }) => {
21    const color = IntentMemoryStorage.get<Color>("color") ?? "systemBlue"
22    return <ResultView content={content} color={color} />
23  }
24})

intent.tsx

1async function runIntent() {
2
3  // 1. 通过 Snippet 请求用户确认颜色
4  await Intent.requestConfirmation(
5    "set",
6    PickColorIntent()
7  )
8
9  // 2. 从 Shortcuts 输入中读取文本
10  const textContent =
11    Intent.shortcutParameter?.type === "text"
12      ? Intent.shortcutParameter.value
13      : "No text parameter from Shortcuts"
14
15  // 3. 创建 SnippetIntent 返回结果
16  const snippetIntentValue = Intent.snippetIntent({
17    snippetIntent: ShowResultIntent({ content: textContent })
18  })
19
20  Script.exit(snippetIntentValue)
21}
22
23runIntent()