WWDC Quick Look 💓 By SwiftGGTeam
Enhanced suggestions for your journaling app

Enhanced suggestions for your journaling app

观看原视频

Highlight

iOS 18 为 Journaling Suggestions API 新增四种资产类型:State of Mind(心理状态)、Motion Activity 跑步类型、Generic Media(第三方媒体)和 Reflection Prompts(反思提示),日记应用无需大幅改代码即可获得更丰富的写作素材。


核心内容

日记应用面临一个核心问题:用户打开应用后不知道写什么。Journaling Suggestions API 在 iOS 17.2 推出时就试图解决这个问题——iOS 自动感知用户生活中的照片、锻炼、地点等事件,把它们作为日记写作的起点建议给用户。上线几个月内,已经有大量应用采纳了这个 API。

iOS 18 把建议的内容变得更丰富了。之前日记应用能拿到的素材限于 Apple 生态内部:Apple Music 的歌曲、Apple Podcasts 的播客、iPhone 检测到的步行。但用户的生活不只在 Apple 应用里发生——他们用第三方 App 听音乐和播客,他们在 Health 里记录情绪,他们有时候需要的只是一个写作提示而不是一段感知数据。iOS 18 的四项更新正是针对这些缺口。

第一项,State of Mind。用户在 Health App 中记录的情绪数据现在可以作为日记建议的一部分出现。第二项,Motion Activity 新增了跑步和混合走路/跑步两种运动类型,覆盖没有 Apple Watch 但经常跑步的用户。第三项,Generic Media 支持用户在非 Apple 应用中消费的音乐和播客内容。第四项,Reflection Prompts 把之前 Apple Journal 独占的反思提示开放给所有开发者。加上横屏支持的自动生效,iOS 18 的 Journaling Suggestions 是一次覆盖面很广的更新。


详细内容

横屏支持(01:59

iOS 17.2 的 Journaling Suggestions 选择器锁定竖屏。iOS 18 起,选择器会自动跟随应用的横竖屏设置。中间的确认界面(用户在此审核将要分享的内容)也利用了更宽的屏幕来展示更大的资产预览。开发者不需要做任何修改,应用支持横屏后选择器自动适配。

State of Mind 资产(02:50

State of Mind 是 iOS 17 在 Health App 中引入的功能,允许用户记录两种情绪样本:瞬时情绪(Momentary Emotions)描述此刻的感受,每日心情(Daily Moods)描述一天的整体感受。每个样本包含三个维度的数据:

  • Valence:效价,表示情绪的正面或负面程度
  • Labels:标签,描述情绪的具体类型,如”平静""满足”等
  • Associations:关联因素,描述什么促成了这个感受,如”家庭""工作""健身”等

State of Mind 建议可以独立出现,也可以附加在已有的出行、活动、在家等建议上。新的资产类型为 JournalingSuggestion.StateOfMind,包含 HKStateOfMind 样本、图片 URL、明暗主题颜色和时间戳。以下是基于 session 中描述的代码模式:

// 从 suggestion 中提取 State of Mind 资产
let stateOfMindItems = suggestion.content.compactMap { $0 as? JournalingSuggestion.StateOfMind }

for item in stateOfMindItems {
    // 用 AsyncImage 展示资产图标
    AsyncImage(url: item.icon)
    // 用自定义函数将效价转为表情符号
    Text(getEmotionEmoji(valence: item.stateOfMind.valence))
}

func getEmotionEmoji(valence: Double) -> String {
    if valence > 0 { return "😊" }
    else if valence < 0 { return "😔" }
    else { return "😐" }
}

关键点:

  • compactMap { $0 as? JournalingSuggestion.StateOfMind } 从建议内容中过滤出 State of Mind 类型的资产
  • item.icon 提供资产的图标 URL,可直接用于 AsyncImage
  • item.stateOfMind.valence 访问效价值,正值表示正面情绪,负值表示负面
  • 开发者可利用 labelsassociations 创建更有表达力的情绪写作体验

Motion Activity 更新(07:20

iOS 17.2 的 Motion Activity 仅支持步行检测(基于 iPhone,无需 Apple Watch)。iOS 18 新增跑步(Run)和混合走路/跑步(Mixed Walk/Run)两种运动类型。资产类型仍为 JournalingSuggestion.MotionActivity,新增 movementType 字段标识运动类型。每种运动类型附带对应的图标。

// 从 suggestion 中提取 Motion Activity 资产
let motionItems = suggestion.content.compactMap { $0 as? JournalingSuggestion.MotionActivity }

for item in motionItems {
    AsyncImage(url: item.icon)
    Text(getMotionActivityLabel(type: item.movementType))
}

func getMotionActivityLabel(type: MovementType) -> String {
    switch type {
    case .running: return "跑步"
    case .walking: return "步行"
    case .mixedWalkRun: return "步行+跑步"
    default: return "运动"
    }
}

关键点:

  • movementType 是新增字段,区分步行、跑步和混合运动
  • 此类建议基于 iPhone 传感器,用户不需要 Apple Watch
  • 运动建议仍可与照片、音乐组合出现

Generic Media(09:17

iOS 17.2 的 Song 和 Podcasts 资产只覆盖 Apple Music 和 Apple Podcasts。iOS 18 新增 JournalingSuggestion.GenericMedia 类型,支持第三方应用中消费的音乐和播客内容。资产包含标题(title)、艺术家(artist)、专辑(album)、应用图标(appIcon)和时间戳。第三方媒体应用通过 Now Playing API 捐赠数据,也可以选择不参与。

// 从 suggestion 中提取 Generic Media 资产
let mediaItems = suggestion.content.compactMap { $0 as? JournalingSuggestion.GenericMedia }

for item in mediaItems {
    AsyncImage(url: item.appIcon)
    if let title = item.title { Text(title) }
    if let artist = item.artist { Text(artist) }
    if let album = item.album { Text(album) }
}

关键点:

  • compactMap { $0 as? JournalingSuggestion.GenericMedia } 过滤出第三方媒体资产
  • appIcon 是播放媒体的应用图标,不是专辑封面
  • titleartistalbum 均不保证存在,取决于捐赠应用提供的数据,使用前必须判空
  • 此类型在设置的 Media 开关下控制

Reflection Prompts(11:39

反思提示是关于感恩、善意、目标等主题的通用写作引导。与基于感知的建议不同,反思提示是通用且无时间限制的——用户随时可以回到同一个提示。这类建议默认启用,在设置中有独立的 Reflection Prompts 开关。用户可以在建议选择器中点击按钮切换不同的提示。

资产类型为 JournalingSuggestion.Reflection,包含提示文本(prompt)和背景颜色(backgroundColor)。

// 从 suggestion 中提取 Reflection 资产
let reflectionItems = suggestion.content.compactMap { $0 as? JournalingSuggestion.Reflection }

for item in reflectionItems {
    item.backgroundColor.map { color in
        Text(item.prompt)
            .foregroundStyle(getForegroundColor(for: color))
            .background(color)
    }
}

func getForegroundColor(for backgroundColor: Color) -> Color {
    // 根据背景亮度选择前景色
    backgroundColor.isLight ? .black : .white
}

关键点:

  • item.prompt 是用户选择的提示文本字符串
  • item.backgroundColor 是建议选择器中展示该提示时使用的颜色,用于在应用中保持视觉一致性
  • 前景色需要根据背景亮度计算,确保文字可读
  • 反思提示默认启用,无需用户手动开启

接入建议(13:54

如果应用不采纳新资产类型,completion block 返回的新内容会被忽略,用户会感到困惑。建议同时支持回退资产类型(UIImageImage),这样即使没有处理所有字段,应用也有基本展示能力。所有数据共享都由用户控制:用户选择建议包含哪些内容、选择发送哪条建议、选择包含哪些资产。


核心启发

  • 做什么:在日记应用中接入 State of Mind 资产,将情绪数据作为日记写作的上下文展示。为什么值得做:情绪与日记写作天然相关,用户在 Health App 中记录的情绪数据可以直接驱动日记内容,降低写作门槛。怎么开始:在现有 compactMap 过滤链中增加 JournalingSuggestion.StateOfMind 类型,用 valencelabelsassociations 构建情绪展示 UI。

  • 做什么:集成 Reflection Prompts 作为每日写作引导功能。为什么值得做:反思提示接入门槛最低(只有一个字符串和一个颜色),但能立即提升应用的写作引导体验,且与”用户不知道写什么”的核心痛点直接对应。怎么开始:过滤 JournalingSuggestion.Reflection 资产,用 prompt 显示引导文本,用 backgroundColor 保持视觉一致性。

  • 做什么:支持 Generic Media 资产,让用户记录在第三方 App 中听的音乐和播客。为什么值得做:很多用户的主力播放器不是 Apple Music,之前这批内容在日记中完全不可见。怎么开始:过滤 JournalingSuggestion.GenericMedia,用 appIcon 区分来源应用,注意 titleartistalbum 字段可能为空,必须做判空处理。

  • 做什么:为 Motion Activity 的新运动类型添加 UI 展示。为什么值得做:跑步用户群体庞大,且这类检测基于 iPhone 不需要 Apple Watch,覆盖了没有手表但经常运动的用户。怎么开始:检查 movementType 字段,为 .running.mixedWalkRun 提供对应的图标和文案。


关联 Session

评论

GitHub Issues · utterances