Highlight
TipKit 让 App 功能提示的创建、展示控制和精准投放变成几行代码的事,支持参数规则和事件规则组合定位目标用户,避免教育信息变成骚扰弹窗。
核心内容
App 里做了好功能,用户却找不到——这是每个开发者都遇到过的困境。传统的做法是在首次启动时做长篇大论的引导页,用户要么快速跳过,要么看完就忘。
TipKit 的思路不同:在正确的时机、向正确的人、展示一句恰到好处的提示。它覆盖 iPhone、iPad、Mac、Apple Watch 和 Apple TV,一套 API 全平台通用。
创建提示
提示由标题和消息组成。标题用直接的动作短语,比如”收藏你喜欢的后院”。消息说明收益,比如”收藏的后院会显示在列表顶部”。(01:53)
提示可以附加图标(SF Symbol)和 Action 按钮。图标帮助用户建立视觉关联,Action 按钮可以跳转到设置页面或引导流程。
但不是所有场景都适合用 TipKit。广告推销、错误消息、功能更新通知、复杂的多步操作指南——这些都不属于用户教育范畴。(02:25)
两种展示方式
Popover:浮层形式,指向特定 UI 元素,不改变当前页面布局。适合引导用户点击某个按钮。tvOS 只支持这种方式。(04:15)
Inline:内嵌形式,App UI 自动让出空间,不会遮挡内容。适合在列表或表单中展示提示。
规则系统
规则是 TipKit 的核心能力,确保提示只展示给最需要的人。(06:02)
参数规则(Parameter-based):基于 Swift 值类型的持久状态。比如用户是否已登录、是否开启了某个设置。
事件规则(Event-based):基于用户行为计数。比如”访问详情页 3 次后才展示提示”。事件可以带时间范围(“过去 5 天内访问 3 次”)和自定义关联类型(“访问同一个后院 3 次”)。
规则可以组合使用。比如”已登录 + 过去 5 天访问详情页 3 次 + 从未收藏过后院”——三个条件同时满足才展示提示。
展示控制
多个提示同时存在时,需要控制展示节奏避免 overwhelm 用户。(09:57)
TipsCenter 提供全局的展示频率控制:
.daily:每天最多展示一个提示.hourly:每小时最多展示一个.immediate:满足条件立即展示,不做频率限制- 自定义
TimeInterval:比如每 5 天一个
单个提示可以设置 .ignoresDisplayFrequency(true) 跳过全局频率限制,适合特别重要的功能引导。也可以设置 .maxDisplayCount(5) 限制总展示次数,超过后自动失效。
提示的消除也有几种方式:用户执行了提示描述的操作(调用 invalidate(reason: .userPerformedAction))、达到最大展示次数、或者开发者根据任意条件调用 invalidate()。(11:27)
测试
TipKit 提供了完整的测试 API,不需要满足规则就能看到提示效果:(12:46)
TipsCenter.showAllTips():展示所有提示TipsCenter.showTips([tip1, tip2]):只展示指定提示TipsCenter.hideAllTips():隐藏所有提示TipsCenter.resetDatastore():清空所有 TipKit 数据
这些也可以通过 Xcode Scheme 的 Launch Arguments 配置,方便快速测试。
详细内容
基础提示定义
import TipKit
struct FavoriteBackyardTip: Tip {
var title: Text {
Text("Save as a Favorite")
}
var message: Text {
Text("Your favorite backyards always appear at the top of the list.")
}
}
关键点:
- 遵守
Tip协议,至少实现title和message title和message返回Text类型,支持 SwiftUI 修饰符- 提示定义是值类型,可以全局创建实例复用
带图标和 Action 的提示
struct FavoriteBackyardTip: Tip {
var title: Text {
Text("Save as a Favorite")
.foregroundColor(.indigo)
}
var message: Text {
Text("Your favorite backyards always appear at the top of the list.")
}
var asset: Image {
Image(systemName: "star")
}
var actions: [Action] {
[
Tip.Action(
id: "learn-more",
title: "Learn More"
)
]
}
}
关键点:
asset用 SF Symbol 或自定义图片,帮助用户建立视觉关联actions数组定义按钮,每个 Action 有唯一 ID 和标题- 在
.popoverMiniTip的回调中通过 action ID 处理点击
初始化配置
@main
struct BackyardBirdsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
init() {
TipsCenter.shared.configure()
}
}
关键点:
TipsCenter.shared.configure()必须在 App 启动时调用- 它负责提示状态和事件数据的持久化
- 不调用的话,事件计数和提示展示状态不会在 App 重启后保留
Popover 展示
private let favoriteBackyardTip = FavoriteBackyardTip()
// ...
.toolbar {
ToolbarItem {
Button {
backyard.isFavorite.toggle()
} label: {
Label("Favorite", systemImage: "star")
.symbolVariant(
backyard.isFavorite ? .fill : .none
)
}
.popoverMiniTip(tip: favoriteBackyardTip)
}
}
关键点:
.popoverMiniTip(tip:)是 SwiftUI 修饰符,自动把提示浮层附加到目标视图- 提示会自动指向修饰符所在的视图元素
- 提示的显示/隐藏由 TipKit 根据规则自动管理,不需要手动控制
参数规则
struct FavoriteBackyardTip: Tip {
@Parameter
static var isLoggedIn: Bool = false
var rules: Predicate<RuleInput...> {
#Rule(Self.$isLoggedIn) { $0 == true }
}
}
关键点:
@Parameter标记的静态属性是持久化的,App 重启后值保留- 在登录成功后设置
FavoriteBackyardTip.isLoggedIn = true #Rule宏定义条件,支持比较运算符和逻辑组合
事件规则
struct FavoriteBackyardTip: Tip {
@Parameter
static var isLoggedIn: Bool = false
static let enteredBackyardDetailView: Event = Event<DetailViewDonation>(
id: "entered-backyard-detail-view"
)
var rules: Predicate<RuleInput...> {
#Rule(Self.$isLoggedIn) { $0 == true }
#Rule(Self.enteredBackyardDetailView) { $0.count >= 3 }
}
}
// 在视图中捐赠事件
.onAppear {
FavoriteBackyardTip.enteredBackyardDetailView.donate()
}
关键点:
Event定义需要唯一 ID,可以带关联类型DonationValue.donate()在事件发生时调用,TipKit 自动记录时间戳$0.count返回该事件的总捐赠次数- 多个
#Rule默认是 AND 关系,必须全部满足
带时间过滤的事件规则
#Rule(Self.enteredBackyardDetailView) {
$0.donations.filter {
$0.date > Date.now.addingTimeInterval(-5 * 60 * 60 * 24)
}
.count >= 3
}
关键点:
$0.donations返回所有捐赠记录,包含date和关联数据- 用
filter筛选时间范围内的记录 - 时间计算用
addingTimeInterval,单位是秒
带关联类型的事件规则
extension FavoriteBackyardTip {
struct DetailViewDonation: DonationValue {
let backyardID: Int
}
}
// 捐赠时附带数据
.onAppear {
FavoriteBackyardTip.enteredBackyardDetailView.donate(
with: .init(backyardID: backyard.id)
)
}
// 规则中按 backyardID 分组统计
#Rule(Self.enteredBackyardDetailView) {
$0.donations.filter {
$0.date > Date.now.addingTimeInterval(-5 * 60 * 60 * 24)
}
.largestSubset(by: \.backyardID)
.count >= 3
}
关键点:
- 关联类型遵守
DonationValue协议,可以存任意可序列化数据 .largestSubset(by:)按指定属性分组,返回最大组的记录数- 这个例子表示”过去 5 天内,访问同一个后院详情页至少 3 次”
- 关联数据越小查询越快,建议只存 ID 不要存完整对象
展示频率配置
// 全局频率:每天一个提示
TipsCenter.shared.configure {
DisplayFrequency(.daily)
}
// 单个提示跳过频率限制
struct FavoriteBackyardTip: Tip {
var options: [Option] {
[.ignoresDisplayFrequency(true)]
}
}
// 单个提示最多展示 5 次
struct FavoriteBackyardTip: Tip {
var options: [Option] {
[.maxDisplayCount(5)]
}
}
关键点:
- 全局频率在
TipsCenter级别配置,影响所有提示 .ignoresDisplayFrequency让单个提示不受全局限制.maxDisplayCount限制提示的总展示次数,达到后自动失效
提示失效
Button {
backyard.isFavorite.toggle()
favoriteBackyardTip.invalidate(reason: .userPerformedAction)
} label: {
Label("Favorite", systemImage: "star")
.symbolVariant(backyard.isFavorite ? .fill : .none
}
.popoverMiniTip(tip: favoriteBackyardTip)
关键点:
.userPerformedAction表示用户执行了提示描述的操作- 调用
invalidate()后提示立即消失,且不会再展示 - 也可以用
.tipClosed表示用户手动关闭,或自定义原因
核心启发
1. 渐进式功能引导系统 做什么:为 App 的核心功能设计一套渐进式提示体系,新用户按顺序发现功能,而不是一次性塞给所有信息。 为什么值得做:TipKit 的规则系统让”在正确时机展示正确提示”变得可编程,用户体验比传统引导页好得多。 怎么开始:列出 App 的 5-10 个关键功能,为每个功能创建 Tip,设置事件规则(如”使用功能 A 3 次后提示功能 B”)。
2. 智能用户分层 做什么:根据用户行为数据,用事件规则自动区分新手、普通用户和高级用户,展示不同的提示。 为什么值得做:同一个提示对新手有用,对老用户就是骚扰。TipKit 的自定义捐赠类型让精细分层成为可能。 怎么开始:定义用户行为事件(如”创建第一个项目”、“使用高级功能 X”),用关联类型记录行为详情,在规则中组合判断用户阶段。
3. 跨设备提示同步 做什么:利用 TipKit 的 iCloud 同步能力,确保用户在 iPhone 上看过的提示不会在 iPad 上重复展示。 为什么值得做:多设备用户越来越多,重复教育会降低产品质感。 怎么开始:TipKit 默认开启 iCloud 同步,无需额外代码。只需要确保各平台的提示 ID 一致。
4. A/B 测试提示文案
做什么:为同一个功能准备多组提示文案,通过事件规则控制展示比例,用转化率数据验证哪组效果更好。
为什么值得做:提示的标题和消息直接影响用户是否愿意尝试新功能,文案优化有明确的 ROI。
怎么开始:创建两个 Tip 类型(如 FavoriteTipVariantA 和 FavoriteTipVariantB),用参数规则控制展示比例,通过 Action 按钮的点击率和功能使用率评估效果。
关联 Session
- Design App Shortcuts — App Shortcuts 的视觉语言设计指南,和 TipKit 同属用户发现体系
- Design dynamic Live Activities — 实时活动的设计原则,学习如何在系统层面展示 App 信息
- Meet SwiftUI for spatial computing — SwiftUI 在空间计算中的新特性,TipKit 同样支持 visionOS
评论
GitHub Issues · utterances