🧠 什么是 SiriKit? #
SiriKit 是 Apple 在 iOS 10 引入的一套系统框架,允许你的 App 被 Siri 调用执行特定任务。它提供一组 “意图(Intent)”类别,比如:
发送消息(Messages)
创建待办(Tasks)
支付(Payments)
预订(RideBooking)
健身(Workout)等
✅ SiriKit 的关键特性: #
特性 | 说明 |
---|---|
使用系统定义的 Intent 类 | 比如 INSendMessageIntent |
基于 Intents Extension | 必须创建 Intents Extension 处理器 |
配置复杂 | 需要额外的目标和 plist 配置 |
被系统严重限制 | 只能处理系统支持的 Intent 类型 |
用户交互有限 | 不能完全定制化语义和体验 |
🚀 什么是 App Intents? #
App Intents 是 Apple 在 iOS 16+ 推出的新框架,目的是取代 SiriKit 的大部分能力,并同时支持:
Siri
Spotlight(搜索建议)
Shortcuts(快捷指令)
App Widgets(iOS 17 可交互 Widget)
App Shortcuts(无需用户手动创建快捷方式)
✅ App Intents 的优势: #
特性 | 说明 |
---|---|
100% Swift 实现 | 使用 AppIntent 协议定义 Intent 类 |
支持参数输入 | 自定义输入参数(枚举、文字、布尔等) |
易于维护和扩展 | 不再需要 Intents Extension |
与 Widget 紧密集成 | 可用于点击 Widget 执行操作 |
与 Siri 深度集成 | 自定义短语就能被 Siri 唤起 |
可配置 UI 显示 | 支持语义标签、分组、分类、权限控制等 |
🧩 App Intents 与 SiriKit 的关系 #
比较维度 | SiriKit | App Intents |
---|---|---|
引入版本 | iOS 10 | iOS 16 |
实现方式 | 基于 Extension(Intents Extension) | 原生 Swift + 主 App 中实现 |
可扩展性 | 固定模板 + 系统意图 | 自定义完全自由 |
Siri 支持 | ✅ 支持(仅限部分用例) | ✅ 完全支持 Siri |
Spotlight 搜索 | ❌ | ✅ 支持自动补全与搜索 |
Widget/Live Activity 支持 | ❌ | ✅ 可与交互式 Widget/Live Activity 配合 |
使用复杂度 | 高(需 Extension、plist) | 低(纯 Swift 实现) |
推荐使用 | ❌(仅用于遗留场景) | ✅(现代统一方式) |
🔁 示例:从 SiriKit 到 App Intents 的进化 #
SiriKit 示例:用户说“发送信息给妈妈” #
你需要使用:
INSendMessageIntent
INSendMessageIntentHandling
协议创建 Intents Extension 并实现
resolveRecipients()
等方法
⚠️ 只能处理 Apple 支持的“发送信息”类场景
App Intents 示例:用户说“开始专注 25 分钟” #
你可以自定义:
struct StartTimerIntent: AppIntent {
static var title: LocalizedStringResource = "开始计时"
@Parameter(title: "类型")
var type: TimerTypeEntity
func perform() async throws -> some IntentResult {
TimerManager.shared.start(type: type.toTimerType())
return .result()
}
}
用户说:“嘿 Siri,开始专注”
→ Siri 触发StartTimerIntent
→ App 启动定时器
🔚 总结:什么时候用 SiriKit?什么时候用 App Intents? #
使用场景 | 推荐技术 |
---|---|
要处理系统预定义的特定语义(如打电话、发短信) | ✅ SiriKit |
自定义任务(如计时器、记录、启动操作) | ✅ App Intents |
为 Widget 添加交互操作 | ✅ App Intents |
为 Shortcuts 提供自动发现的快捷入口 | ✅ App Intents |
快速响应 Siri 自然语言命令 | ✅ App Intents(更智能) |
如果你正在开发的是一个现代 iOS 应用(尤其是支持 Siri、快捷指令、Widget 的),优先使用 App Intents。
可以说,SiriKit 正在被边缘化,但尚未完全过时。以下是详细解释:
🧓 SiriKit 的现状:正在被 App Intents 替代 #
✅ SiriKit 仍可用,但局限越来越明显: #
SiriKit 仍支持系统级任务(如发短信、打车、锻炼、CarPlay)
Apple 没有宣布废弃 SiriKit,但从 iOS 16 开始就几乎不再更新其功能
文档中多次鼓励开发者转向 App Intents
新功能(如 Widget 交互、Spotlight 搜索、App Shortcuts)完全不支持 SiriKit
📈 App Intents 是 SiriKit 的现代替代者 #
特性 | SiriKit | App Intents |
---|---|---|
系统级任务(如打车) | ✅ 强项 | ❌ 无法取代 |
自定义任务 / 操作 | ❌ 受限 | ✅ 推荐方式 |
与 Widget 交互 | ❌ 不支持 | ✅ 深度整合 |
无需 Extension | ❌ 必须要 | ✅ 直接 Swift 实现 |
多平台支持 | iOS/watchOS/macOS(有限) | ✅ 全面支持 |
快捷指令自动集成 | ❌ 需要配置 | ✅ 零配置自动曝光 |
📌 官方态度 #
虽然 Apple 没有宣布“废弃 SiriKit”,但以下信号很明显:
Xcode 模板默认引导使用 App Intents,而非 SiriKit
Apple 在 WWDC 2022 和 2023 中大力推广 App Intents
快捷指令 / Widget / Spotlight / Siri 全部统一使用 App Intents 架构
新文档几乎不再更新 SiriKit 的新能力
✅ 实践建议(2024–2025年): #
需求 | 建议 |
---|---|
发短信、打开地图、播放音乐等系统行为 | 使用 SiriKit |
启动自定义功能、计时器、记录、切换状态等 | 使用 App Intents |
面向未来(Siri、Widget、搜索等统一入口) | 构建在 App Intents 上 |
🧠 一句话总结: #
SiriKit 是过去的桥梁,App Intents 是现在和未来的高速路。
如果你在构建一个新项目,强烈推荐完全使用 App Intents 来取代你过去在 SiriKit 中想做的事情。
如果需要,我可以帮你将一个 SiriKit 场景“迁移”到 App Intents 的写法,看看效果对比?
示例 #
我们来实现一个完整可用的 Siri 命令 + AppIntent 示例:用户说「嘿 Siri,开始长休息」就能触发一个 长休息计时器(你也可以换成专注、短休息等)。
🧱 整体目标 #
使用 Swift 实现
AppIntent
支持 Siri 语音命令「开始长休息」
启动你自己的倒计时逻辑
支持 Widget、快捷指令、Spotlight 自动集成(自动展示,不用手动添加)
✅ 第一步:创建 TimerTypeEntity.swift
#
enum TimerType: String, CaseIterable, Codable {
case focus = "专注"
case shortBreak = "短休息"
case longBreak = "长休息"
var duration: TimeInterval {
switch self {
case .focus: return 25 * 60
case .shortBreak: return 5 * 60
case .longBreak: return 15 * 60
}
}
}
如果你想让 Siri 能识别「长休息」「专注」,你还需要声明一个 AppEntity
:
import AppIntents
struct TimerTypeEntity: AppEntity, Identifiable, Hashable {
let id: String
let type: TimerType
static var typeDisplayRepresentation: TypeDisplayRepresentation = "计时器类型"
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(type.rawValue)")
}
static var defaultQuery = TimerTypeQuery()
// 提供可选择列表
struct TimerTypeQuery: EntityQuery {
func entities(for identifiers: [String]) async throws -> [TimerTypeEntity] {
TimerType.allCases
.filter { identifiers.contains($0.rawValue) }
.map { TimerTypeEntity(id: $0.rawValue, type: $0) }
}
func suggestedEntities() async throws -> [TimerTypeEntity] {
TimerType.allCases.map { TimerTypeEntity(id: $0.rawValue, type: $0) }
}
}
}
extension TimerTypeEntity {
func toTimerType() -> TimerType { type }
}
✅ 第二步:实现 AppIntent —— StartTimerIntent
#
struct StartTimerIntent: AppIntent {
static var title: LocalizedStringResource = "开始计时器"
static var description = IntentDescription("开始一个指定类型的计时器")
@Parameter(title: "计时器类型")
var timerType: TimerTypeEntity
static var openAppWhenRun: Bool = true // Siri 执行时是否打开 App
func perform() async throws -> some IntentResult {
let type = timerType.toTimerType()
// 启动你的计时器逻辑
TimerManager.shared.start(type: type)
return .result(dialog: "已开始\(type.rawValue)计时")
}
}
☝️ Siri 会自动读取 title + parameter,并且使用 displayRepresentation 自动生成语音命令。
✅ 第三步:让 App 支持 Siri / AppIntents #
你需要在你的 App 的 Info.plist
添加权限描述字段:
<key>IntentsSupported</key>
<array>
<string>StartTimerIntent</string>
</array>
然后确认你的主 App(不是 Widget Extension)已经:
添加了
AppIntents
框架把
StartTimerIntent
放在主 App 中(不是 Widget 里)
✅ 第四步:调用计时器逻辑(例子) #
final class TimerManager {
static let shared = TimerManager()
func start(type: TimerType) {
print("已开始 \(type.rawValue),持续 \(type.duration) 秒")
// 实际可触发 Live Activity、通知等逻辑
}
}
🗣️ Siri 调用演示 #
现在你可以直接对 iPhone 或 Simulator 说:
嘿 Siri,开始长休息
或使用 Spotlight 搜索「开始长休息」,或者进入快捷指令 app,AppIntent 会自动出现!
🚀 加强体验建议(可选) #
项目 | 建议 |
---|---|
添加 Widget 时用这个 AppIntent 做入口 | ✅ 可点击 Widget 直接触发 |
添加 Live Activity 展示倒计时 | ✅ 锁屏同步状态 |
添加语音反馈(dialog: ) | ✅ 已使用 |
添加 Siri Shortcuts 图标 | ✅ 可在 Shortcut App 设置 |
✅ 总结 #
你现在已经完成一个完整 Siri 命令集成的 AppIntent 示例,实现了用自然语言指令启动自定义功能。
这就是 AppIntents 统一 Siri + Widget + Shortcuts 的强大之处。
Live Activity 效果 #
很好!我们在前面已经完成了 Siri + AppIntent
启动计时器,现在再加上 Live Activity,实现用户说“开始长休息”之后:
自动触发 Live Activity
在锁屏 / 动态岛 / 主屏上显示实时倒计时
🎯 整体结构 #
我们会加入以下内容:
ActivityAttributes
定义计时器属性LiveActivityManager
启动 Live Activity修改
TimerManager
在开始计时时启动 Live ActivityDynamicIsland
/锁屏 UI 更新
✅ 第一步:定义 TimerActivityAttributes
#
import ActivityKit
struct TimerActivityAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var endTime: Date
}
var title: String
}
title
: 如「长休息」endTime
: 用于倒计时结束时间
✅ 第二步:创建 LiveActivityManager #
import ActivityKit
final class LiveActivityManager {
static let shared = LiveActivityManager()
private var currentActivity: Activity<TimerActivityAttributes>?
func startActivity(for type: TimerType) {
let endTime = Date().addingTimeInterval(type.duration)
let attributes = TimerActivityAttributes(title: type.rawValue)
let state = TimerActivityAttributes.ContentState(endTime: endTime)
do {
currentActivity = try Activity<TimerActivityAttributes>.request(
attributes: attributes,
contentState: state,
pushType: nil
)
} catch {
print("🚨 启动 Live Activity 失败: \(error)")
}
}
func stopActivity() {
Task {
await currentActivity?.end(dismissalPolicy: .immediate)
}
}
}
✅ 第三步:修改 TimerManager 启动 Live Activity #
final class TimerManager {
static let shared = TimerManager()
func start(type: TimerType) {
print("已开始 \(type.rawValue),持续 \(type.duration) 秒")
LiveActivityManager.shared.startActivity(for: type)
}
}
✅ 第四步:实现 Live Activity 的 UI(锁屏 & 动态岛) #
你需要在 Widget Extension 中添加:
TimerWidgetLiveActivity.swift
#
import ActivityKit
import WidgetKit
import SwiftUI
struct TimerWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerActivityAttributes.self) { context in
// 锁屏 UI
VStack {
Text(context.attributes.title)
.font(.headline)
CountdownView(to: context.state.endTime)
}
.padding()
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.center) {
VStack {
Text(context.attributes.title)
.font(.headline)
CountdownView(to: context.state.endTime)
}
}
} compactLeading: {
Text("⏱")
} compactTrailing: {
CountdownView(to: context.state.endTime)
.font(.caption)
} minimal: {
Text("⏱")
}
}
}
}
添加倒计时视图组件 #
struct CountdownView: View {
let to: Date
@State private var now = Date()
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Text(remainingTime)
.onReceive(timer) { _ in now = Date() }
}
var remainingTime: String {
let diff = Int(to.timeIntervalSince(now))
let m = diff / 60
let s = diff % 60
return String(format: "%02d:%02d", m, s)
}
}
✅ 第五步:在 Widget Extension 中注册 Live Activity #
确保 @main
中包含:
@main
struct MyTimerWidgets: WidgetBundle {
var body: some Widget {
TimerWidgetLiveActivity()
// 可添加普通 Widget 等
}
}
✅ 权限设置 #
在主 App 的 Info.plist
添加:
<key>NSUserActivityTypes</key>
<array>
<string>com.apple.activitykit.activity</string>
</array>
✅ 运行效果 #
用户说:「嘿 Siri,开始长休息」
Siri 启动
StartTimerIntent
启动你的计时器逻辑 + Live Activity
动态岛 / 锁屏 显示倒计时!
✅ Bonus:Live Activity 结束自动关闭 #
你可以用 DispatchQueue.main.asyncAfter
或计时器监听倒计时结束,调用:
LiveActivityManager.shared.stopActivity()