Add intelligence to your widgets
System & Services 进阶 22m

为小组件添加智能推荐

Add intelligence to your widgets

2021年6月9日

在 Apple 官方观看视频

一句话判断

WidgetKit 在 iOS 15 拿到了「智能推荐」的入场券——你的 Widget 可以被 Siri 建议自动展示在主屏上,但这需要你正确配置 Intent 和 Donation。

这场 Session 讲了什么

iOS 15 中的 Widget 获得了一个重要的新分发渠道:Siri 智能建议。当系统判断用户可能需要你的 Widget 时,会自动在主屏的 Smart Stack 中展示它。这个机制依赖 INRelevantShortcutStore 和 Intent 的 Donation。

Session 讲解了如何让你的 Widget 「可被推荐」。你需要做三件事:创建一个可配置的 Widget(使用 IntentConfiguration),在 app 中 Donate 相关的 INIntent,然后让系统在合适的时间展示你的 Widget。

典型场景:用户每天早上 7 点用你的 app 查看日程。系统学习到这个模式后,会在早上 7 点自动把你的日程 Widget 放到 Smart Stack 的顶部。用户只需要在主屏上滑动就能看到今天的日程。

另外还介绍了 Widget 的「 Reyes 」(Relevance)优化。你可以通过 RelevantShortcutManager 告诉系统你的 Widget 在什么场景下最有用(比如某个地点、某个时间段),系统会据此决定是否展示。

值得深挖的点

Intent Donation 的最佳时机

Intent Donation 不是越多越好。如果你在用户每次点击按钮时都 Donate 一个 Intent,系统会被大量信号淹没,反而无法学到有效的模式。Session 建议:只在用户完成了一个「完整的动作」后才 Donate。比如用户查看了某个城市的天气,Donate 一个「查看天气」的 Intent 并附带城市参数。

Smart Stack 的排序逻辑

Smart Stack 的排序由系统自动完成,开发者无法控制。但你可以通过设置 INRelevantShortcutrelevanceScore 来影响排序。score 越高,Widget 被展示的概率越大。建议根据用户的使用频率和最近使用时间来计算 score。

代码片段

// 配置可被 Siri 推荐的 Widget
import WidgetKit
import Intents

// 定义 Widget 的配置 Intent
class CityConfigurationIntent: INIntent {
    @NSManaged var city: String?
}

// 在 TimelineProvider 中使用 Intent
struct WeatherIntentProvider: IntentTimelineProvider {
    func placeholder(in context: Context) -> WeatherEntry {
        WeatherEntry(date: Date(), city: "北京", temperature: 22)
    }
    
    func getSnapshot(for configuration: CityConfigurationIntent, 
                     in context: Context, 
                     completion: @escaping (WeatherEntry) -> Void) {
        let city = configuration.city ?? "北京"
        completion(WeatherEntry(date: Date(), city: city, temperature: 22))
    }
    
    func getTimeline(for configuration: CityConfigurationIntent, 
                     in context: Context, 
                     completion: @escaping (Timeline<WeatherEntry>) -> Void) {
        let city = configuration.city ?? "北京"
        // 根据城市获取天气数据并生成时间线
        let entries = generateEntries(for: city)
        completion(Timeline(entries: entries, policy: .atEnd))
    }
}
// 在 app 中 Donate Intent
import Intents

func donateViewWeatherIntent(city: String) {
    let intent = ViewWeatherIntent()
    intent.city = city
    intent.suggestedInvocationPhrase = "查看\(city)天气"
    
    let interaction = INInteraction(intent: intent, response: nil)
    interaction.donate { error in
        if let error = error {
            print("Donate 失败: \(error)")
        }
    }
}
// 设置相关快捷方式,提升推荐概率
import Intents

func updateRelevantShortcuts() {
    var shortcuts: [INRelevantShortcut] = []
    
    // 为常用城市创建相关快捷方式
    let cities = ["北京", "上海", "深圳"]
    for city in cities {
        let intent = ViewWeatherIntent()
        intent.city = city
        
        let shortcut = INShortcut(intent: intent)
        let relevantShortcut = INRelevantShortcut(shortcut: shortcut)
        
        // 设置相关度评分
        relevantShortcut.shortcutRole = .information
        
        // 设置场景:每天早上推荐
        let morningDate = Calendar.current.date(bySettingHour: 7, minute: 0, second: 0, of: Date())!
        relevantShortcut.relevanceProviders = [
            INDateRelevanceProvider(start: morningDate, end: morningDate.addingTimeInterval(3600))
        ]
        
        shortcuts.append(relevantShortcut)
    }
    
    INRelevantShortcutStore.default.setRelevantShortcuts(shortcuts) { error in
        if let error = error {
            print("更新相关快捷方式失败: \(error)")
        }
    }
}

最佳实践

不要为了获得更多推荐而频繁 Donate Intent。系统的智能推荐模型会过滤掉过于频繁的 Donation。一天 Donate 2-3 次比一天 Donate 50 次效果好得多。

为你的 Widget 配置 suggestedInvocationPhrase,这会让用户在用 Siri 语音控制时更容易触发你的 Widget。短语应该自然且简短,比如「查看天气」比「打开天气应用查看当前城市的天气预报」好得多。

还有什么值得关注

  • INRelevantShortcutStore 支持 INLocationRelevanceProvider,可以根据用户的位置触发推荐。
  • Widget 的 Smart Stack 推荐在 iPadOS 15 上也可用。
  • 用户可以手动将 Widget 添加到 Smart Stack 中,系统会学习用户的偏好来优化排序。
WWDC 2021