Apple Intelligence:从AppIntents开始看Apple AI

1,221 阅读11分钟

引言

飞书知识库

背景

AI技术在苹果生态系统中的落地一直是大家期待的。随着2024年全球开发者大会(WWDC)的结束,Apple终于算是交卷了。虽然各界对这些成果的评价褒贬不一,但作为开发者,我们更关注技术层面的API更新。单从数量上看,苹果给足了诚意,各位iOS老乡,我们可以慢慢消化了。

在众多API更新中,"Apple Intelligence"无疑是最引人注目的。本文将从AppIntents开始,逐步深入探讨相关技术文档,力求更全面的认识“苹果对AI交互的理解”。

阅读指南

问题:如何发挥系统与App的协同能力

AppIntents框架

概述

框架优势 :使用AppIntents,让你的App在Siri, Apple Intelligence, Spotlight, controls, widgets, the Action button中被发现

丰富你的App入口:

框架图

  • 架构展示,为什么可以做到

  三个核心概念

Note:AppShortcuts限制10个以内

AppIntent

协议: App支持的Intent意图,包含意图描述的元数据信息,和perform执行方法

AppEntity

参数或返回数据实体,自定义数据类型的包装,可开放给shortcut用于参数配置

image.png

AppShortcut

包含intent、短语phrases、shortTitle短标题、systemImageName图、parameterPresentation展示配置

AppShortcutsProvider: 通过 "static var appShortcuts"把Shortcuts的能力告知系统System,“updateAppShortcutParameters”shortcuts更新告知System

Note:shortcuts设置的Shortcuts,展示最先,使用频度最高

系统协同-开发指南

1.重新审视你的App价值

让你的App服务,触手可及

比如:利用Siri可执行你的App Action;利用Shortcut跨平台能力协同;减少用户分心的干扰,只专注于用户聚焦的意图。

see App intent domains and Integrating your app with Siri and Apple Intelligence.

2. 充分理解AppIntents API的体验

  • 使用AppIntents框架,添加Actions和content的描述信息

同时结合各Kit的能力,

  • WidgetKit :可交互的、可配置的widgets,手表complications和调控控件Control
  • ActivityKit : 提供实时可交互数据(共享来自你的App实时更新,在灵动岛、锁屏以及watchOS的智能叠层上显示。)

3. 计划适配AppIntents

AppIntents框架,可以理解为系统Apps的基础功能块block,可以接受参数 、执行特定的Perform、返回Result,但是可以被系统级的服务调用,拥有更广的服务体验。据此,评估你的App功能和内容,合理的使用AppIntents。

适配路线:

AppIntents Framework升级(Siri和Apple Intelligence支持), 重审当前的AppIntents,考虑更多的action和content使用AppIntents

5.考虑移除AppIntent的影响

在采用App Intents框架时,请牢记这一点,并考虑为你的AppIntent代码制定一个弃用策略。当你计划移除一个AppIntent时,提前通知用户你的意图。发布一个版本,在其中将现有的AppIntent更改为DeprecatedAppIntent,并提供一个建议的替代方案。在给予用户足够的时间更新他们的自定义快捷方式并迁移到新的应用快捷方式后,再从你的应用中移除 DeprecatedAppIntent

6. When & How: 迁移到AppIntents

Siri和Apple Intelligence会自动利用SiriKit意图。如果你移除使用SiriKit的代码,提前通知用户这些变化,以避免破坏他们现有的自定义快捷方式,并确保提供使用App Intents的相同或可比功能。

SiriKit到AppIntents迁移建议:Soup Chef with App Intents: Migrating custom intents.

让你的App无所不在

Siri可用

使用 App intent domains 使得 AppEnum, AppEntity, and AppIntent 被Siri展示

Spotlight可用

遵守IndexedEntit 协议

Core Spotlight —Section视频介绍

Core Spotlight | 开发文档

说明:

  1. 可以控制搜索你App内的内容
  2. 使用NSUserActivity的搜索相关属性将项目添加到设备上的索引中,并带有将项目标识为符合公共索引条件的选项。在索引活动和导航点中。了解更多NSUserActivity in Index Activities and Navigation Points.
  3. 使用web标记索引你的web服务器上的内容,这使得所有iOS用户都可以在Spotlight和Safari搜索结果中获得数据。有关更多信息,Mark Up Web Content in App Search Programming Guide.

NSUserActivity+Handoff跨设备协同

App瞬时状态,用于Handoff多设备协同,跨设备继续用户操作活动。

更多参考:专题:Handoff 跨设备协同

Siri

  • SiriKit需要启动你的App,会传递一个NSUserActivity 对象衔接用户交互
  • iOS15 支持asking Siri to “share this”. 同时Shortcut “识别屏幕内容”可查看的页面内容

QuickNote-快捷链接

可以链接到任何以NSUserActivity表示的应用内容,显示为链接

详细规则:Quick Note

Search result-搜索结果

提供NSUserActivity给Spotlight,影响搜索结果,详细内容:Search results

App间共享

Transferable protocol

Demo:Code: Making your app’s functionality available to Siri

最佳实践

AppIntents的高阶应用-ER图

image.png

image.png

  • AppIntent

协议: App支持的Intent意图,包含意图描述的元数据信息,和perform执行方法

子协议: Apple Watch运动Intent :StartWorkoutIntent、 PauseWorkoutIntent、 ResumeWorkoutIntent

// 是否需要打开App

static var openAppWhenRun: Bool = true

  • 基本数据类型参数 + ForegroundContinuableIntent
struct SuggestTrails: ForegroundContinuableIntent {
static var title: LocalizedStringResource = "Suggest Trails"
    
    /// The `resultValueName` parameter names the output of the intent to control how the system displays it when other actions use it in a shortcut.
    static var description = IntentDescription("Plan your next trip to the great outdoors with some suggestions on what you'll enjoy doing.",
                                               categoryName: "Discover",
                                               resultValueName: "Suggested Trails")
    
    /// When this intent runs, the system launches the app in the background without creating any UI scenes.
    static var openAppWhenRun: Bool = false

 @Parameter(title: "Activity", requestValueDialog: "What activity would you like to do?")
    var activity: ActivityStyle
    
    /**
     Measurement parameters can provide their preferred unit with the `defaultUnit` parameter, and also specify whether the unit can have a
     negative value. The default unit selected here is visible when configuring the intent in Shortcuts.
     */
    @Parameter(title: "Search Radius", defaultUnit: .kilometers, supportsNegativeNumbers: false)
    var searchRadius: Measurement<UnitLength>?

    @Parameter(title: "Location", requestValueDialog: "Where would you like to go?", optionsProvider: LocationOptionsProvider())
    var location: String?
    
    @Parameter(title: "Featured Collection")
    var trailCollection: TrailCollection?
    // 省略 code
}
  • 自定义数据参数
struct GetTrailInfo: AppIntent {
    
    static var title: LocalizedStringResource = "Get Trail Information"
    static var description = IntentDescription("Provides complete details on a trail, including the permitted activities and the current conditions.",
                                               categoryName: "Discover")
    
    /**
     A sentence that describes the intent, incorporating parameters as a natural part of the sentence. The Shortcuts editor displays this sentence
     inline. Without the parameter summary, the Shortcuts editor displays the `trail` parameter as a separate row, making the intent harder to
     configure in a shortcut.
     */
    static var parameterSummary: some ParameterSummary {
        Summary("Get information on (.$trail)")
    }

    /**
     The trail this intent gets information on. Either the individual provides this parameter when the intent runs, or it comes preconfigured
     in a shortcut.
     - Tag: parameter
     */
    @Parameter(title: "Trail", description: "The trail to get information on.")
    var trail: TrailEntity
    
    @Dependency
    private var trailManager: TrailDataManager
    // 省略 code
}
  • AppEntity
struct TrailEntity: AppEntity {

    /**
     A localized name representing this entity as a concept people are familiar with in the app, including
     localized variations based on the plural rules defined in the app's `.stringsdict` file (referenced
     through the `table` parameter). The app may show this value to people when they configure an intent.
     */
    static var typeDisplayRepresentation: TypeDisplayRepresentation {
        TypeDisplayRepresentation(
            name: LocalizedStringResource("Trail", table: "AppIntents"),
            numericFormat: LocalizedStringResource("(placeholder: .int) trails", table: "AppIntents")
        )
    }
    
    /**
     Provide the system with the interface required to query `TrailEntity` structures.
     - Tag: default_query
     */
    static var defaultQuery = TrailEntityQuery()
        // 省略 code
}

TransientAppEntity: 瞬态类型实体,不参与查询

  • EntityQuery

为系统执行Siri、shortcut检索时提供接口

struct TrailEntityQuery: EntityQuery {
    
    @Dependency
    var trailManager: TrailDataManager
    
    /**
     All entity queries need to locate specific entities through their unique ID. When someone creates a shortcut and populates fields with
     specific values, the system stores and looks up the values through their unique identifiers.
     
     - Tag: query_by_id
     */
    func entities(for identifiers: [TrailEntity.ID]) async throws -> [TrailEntity] {
        Logger.entityQueryLogging.debug("[TrailEntityQuery] Query for IDs (identifiers)")
        
        return trailManager.trails(with: identifiers)
                .map { TrailEntity(trail: $0) }
    }
    
    /**
     - Returns: The most likely choices relevant to the individual, such as the contents of a favorites list. The system displays these values as
     a list of options for the entities. For example, configuring the Get Trail Info intent in the Shortcuts app will show these values
     as suggestions for the trail parameter.
     
     - Tag: suggested_entities
     */
    func suggestedEntities() async throws -> [TrailEntity] {
        Logger.entityQueryLogging.debug("[TrailEntityQuery] Request for suggested entities")
        
        return trailManager.trails(with: trailManager.favoritesCollection.members)
                .map { TrailEntity(trail: $0) }
    }
}

EnumerableEntityQuery、DynamicOptionsProvider

  • EntityPropertyQuery: 提供按属性排序sort、匹配match能力
extension TrailEntityQuery: EntityPropertyQuery {
/// Performs the Find intent using the predicates that the individual enters in the Shortcuts app.
    func entities(matching comparators: [Predicate<TrailEntity>],
                  mode: ComparatorMode,
                  sortedBy: [EntityQuerySort<TrailEntity>],
                  limit: Int?) async throws -> [TrailEntity] { // code }
}

使用建议

  • App内 Siri建议弹框
// 展示Siri 建议的UI
SiriTipView(intent: OpenFavorites(), isVisible: $displaySiriTip)
  • App跳转Shortcut 自家App支持的Shortcut页面
/// `ShortcutsLink` opens this app's page in the Shortcuts app, so the user can see all of the App Shortcuts provided by the app.
ShortcutsLink(action: {
                    print("I'm gotoing shortcut!")
                }).shortcutsLinkStyle(.automatic)

Demo:Accelerating app interactions with App Intents

实践:创建你的首个App Intent

Creating your first app intent.

Accelerating app interactions with App Intents | Apple Developer Documentation

Apple Intelligence适配

利用Siri和Apple Intelligence增强的操作功能,创建符合助手模式的Intents、实体和枚举。

  • 了解Apple Intelligence的助手模式

为了将你的应用与Siri和Apple Intelligence集成,你需要提供AppIntent、AppEntity和AppEnum的实现,这些实现能够很好地与Apple Intelligence使用的预训练模型配合工作。为此,你可以使用Swift宏来生成额外的属性并为你的应用意图、应用实体和应用枚举实现添加协议一致性,这些都是Apple Intelligence所需要的。Xcode提供了模板,使得创建这些新实现变得容易,并在编译时验证代码的协议一致性。

要创建与Siri和Apple Intelligence良好配合的实现:

  • 对于你的App Intents实现,使用AssistantIntent(schema:)宏。
  • 对于你的AppEntity实现,使用AssistantEntity(schema:)宏。
  • 对于你的AppEnum实现,使用AssistantEnum(schema:)宏。

每个宏都需要你提供一个schema值,以生成Apple Intelligence能够理解的应用意图、应用实体或应用枚举代码。你提供给宏的值,即助手模式,有两个部分:

  1. 应用意图域:描述特定功能的API集合;例如,如果应用具有照片或视频功能,则为.photos域。
  2. 模式:域中的一个动作或内容类型,即你创建的应用意图、应用实体或应用枚举的特定API。

例如,一个从照片库中打开照片的应用意图使用@AssistantIntent(schema: .photos.openAsset),以确保该意图提供必要的元数据,使Apple Intelligence能够很好地理解它。

重要提示:

只能使用提供的应用意图域和模式,进行与特定域和模式匹配的应用操作和内容。

有关可用助手模式的列表,请参见App intent domains.

  • 检查Schema要求

在遵循助手模式时,需要满足一些要求,这些要求因域和模式的不同而有所变化。

所有助手模式都共享以下约束:

  1. 应用意图(App Intents)

    1. 应用意图不能要求除了模式预期之外的参数。如果你的应用意图使用了额外的参数,必须将它们设为可选。
    2. 仅在应用意图出现在快捷指令(Shortcuts)应用中时,扩展模式的可选参数才可用。
  2. 应用实体(App Entities)

    1. 应用实体不能使用除了模式预期之外的必需属性。但可以使用可选属性。
  3. 应用枚举(App Enums)

    1. 应用枚举在其枚举案例上没有特定要求,提供了完全的灵活性。
    2. 但是,不能使用超过总共10个符合助手模式的应用枚举。

这些约束确保了应用与Apple Intelligence和Siri的集成过程中的一致性和兼容性。通过遵循这些约束,你可以创建与Apple的预训练模型良好配合的应用功能。

  • 创建一个AppIntent 实现助手模式

详见Create an app intent that implements a schema

说明:编译后,系统不再需要您之前提供的元数据,如标题或描述。移除它们可以简化您的代码。

  • *原有AppIntent兼容,支持App Intelligence

新建一个App Intent设置 isAssistantOnly 为true

延伸阅读

参考

  1. 官方文档
  • AppIntents 新功能

    •   概览:了解App Intents的改进和提升,以及如何使用Transferable API、File Representations、Item Providers和Spotlight Indexing等功能,将你的App功能公开给Siri和其他新功能
  • 利用 App Intents 提供App 的核心功能

    •   概览:了解App Intents框架的要素(如意图、实体和查询),以及如何利用这些要素显示App最重要的功能以满足用户需求
  • Core Spotlight 支持语义搜索 (提升用户留存方案)

  • 利用 App Intents 设计提升系统体验

    •   App Intents 为控件、“聚焦”、Siri 等方面的系统体验提供了强大支持。了解如何识别最适合 App Intents 的功能,以及如何利用参数让此类意图更灵活。了解如何使用 App Intents 让用户在你的 App 之外完成相关操作,并通过几个示例了解应在何时导航到自己的 App 来显示情境信息
  • 探索 App Intents 的增强功能

    •   使用 App Intents 让你的小部件生动活泼!探索最新更新并了解如何利用动态选项和用户交互性为你的 App 快捷指令构建更好的体验。我们将分享如何与 Apple Pay 集成、更有效地构建代码以及将快捷指令 App 集成提升到新的水平。
  1. SiriKit开发文档

     Intents 和 IntentsUI 框架可驱动以 “Hey Siri...” 开头的交互指令、快捷指令操作以及小组件配置。该系统还可将来自于您的 app 的 intent 和用户活动整合到地图、日历、复杂型腕表、小组件以及搜索结果的上下文建议中。使用该系统提供的标准 intent 可授权执行用户向 Siri 请求的操作,例如播放音乐或发送短信等。您也可以通过设计自定义 intent 在整个系统中提供您的 app 所独有的功能。