View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

返回 WWDC25

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 了解 App Intents

    了解 App Intents 框架及其在 Apple 开发者平台中愈显关键的作用。我们将向你全面介绍意图、实体、查询等核心概念。你将了解如何综合运用这些概念,以便使你的 App 与 Apple 设备 (从“聚焦”和“快捷指令”等软件功能到操作按钮等硬件功能) 实现整合。我们还将介绍如何将 App Intents 作为你 App 的入口,以便将来实现与 Apple 智能的整合。

    章节

    • 0:00 - Introduction
    • 0:45 - App Intents ecosystem
    • 2:47 - Navigating the framework
    • 21:15 - How it works

    资源

    • Accelerating app interactions with App Intents
    • Adopting App Intents to support system experiences
    • App intent domains
    • App Intents
    • App Shortcuts
    • Building a workout app for iPhone and iPad
    • Creating your first app intent
    • Integrating actions with Siri and Apple Intelligence
    • Making actions and content discoverable and widely available
      • 高清视频
      • 标清视频

    相关视频

    WWDC25

    • 使用 App Intents 针对“快捷指令”和“聚焦”进行开发
    • 设计交互式摘要卡片

    WWDC24

    • 利用 App Intents 为用户奉上 App 的核心功能
    • 利用 App Intents 设计提升系统体验
    • 带你的 App 登陆 Siri
    • App Intents 的新功能
  • 搜索此视频…

    Hi, I’m James,and I’m an engineering manager on the Swift Intelligence Frameworks team.

    I’m excited to talk to you about App Intents, a framework that lets you extend your app's discoverability, visibility, and capabilities all across the system, and on all Apple platforms. I’ll start by talking about the increasingly important role App Intents plays within Apple’s developer ecosystem.

    Next, I’ll show you how to use the framework to make your app’s actions and entities available to people throughout the system.

    I’ll end by sharing some important details you should know when writing your App Intents.

    Before we discuss how you can use App Intents, we should talk about the, "Why." App Intents is more than the framework you bring INto your application to build features. It’s an ecosystem that enables your app’s functionality to expand OUT across the system.

    App Intents lets you offer your users customized results in Spotlight, context-aware experiences for the Action Button, configurability and interactivity in Widgets, easy-to-access controls in Control Center, and even custom actions for Apple Pencil Pro.

    New this year, Spotlight can now invoke your app’s actions from anywhere on the Mac.

    The App Intents framework lets you provide these rich experiences to your customers, even when they’re not in your app. It all starts with the actions your app can perform, such as opening a note, starting a workout, or adding an item to a grocery list. These are the verbs of your app, and, as you may have guessed, you describe them by creating App Intents, or intents for short. When you create an intent, you provide the system with additional information to properly perform the action. Intents can take parameters and return values. These inputs and outputs can be native Swift types or types you define in your app. You can create two flavors of values with App Intents. Use an App Enum for your types with a constant set of values, and for dynamic types, use an App Entity. App Enums and App Entities are the nouns in your app.

    App Shortcuts lets you elevate your key intents, making them more accessible and discoverable.

    App Shortcuts are surfaced when searching in Spotlight, using Siri, configuring the Action Button, and more.

    You can consider these as the sentences of your app, made from an intent and any parameters the intent needs to run.

    I’ve always found the best way to learn, is by doing. Let’s check out what it takes to create my first intent.

    I love to travel with my family, and I’ve been working on an app to check out famous landmarks throughout the world. My app has a few sections. I can scroll through a list of famous landmarks, check out them on a map, or view collections I’ve created.

    Many users enjoy scrolling the grid of landmarks. I’ll build an App Intent to make navigating directly to this part of the app more convenient.

    So, how do I do that? I’ll start by defining a new struct that adopts the App Intents protocol.

    The minimum requirements for an App Intent are a title and a perform method.

    The title is a unique, localized string which will appear as the name of the intent. The perform method contains the intent’s logic. I’ll use a shared navigator to open the Landmarks view. Navigation must be done on the main thread, so I’ll mark perform with @MainActor.

    The perform method returns an Intent Result.

    Intent Results can contain a number of things, including dialog that Siri can speak and a view snippet to show. By default, performing an intent will not foreground your app, so providing dialog and a snippet are a great way to show the result of your action.

    Since this intent is designed to navigate screens in the app, I’ll configure the intent to open when it’s run.

    I’ll set the new supportedModes property to foreground to open my app before the intent is performed, and that’s all it takes to build my first intent. After installing my app, intents can be found in Shortcuts. I can build a new Shortcut and add my navigation intent. Running it will foreground my app and bring me directly to the Landmarks view. My app also has sections for viewing collections and displaying landmarks on a map. It would be great if the intent could also navigate to those parts of the app. My app uses a simple Swift enum to model sections. To make the type compatible with the framework, I’ll adopt the App Enum protocol. App Enums only have a few requirements. They must be instantiable from a string, so I’ll add a String raw value. A Type Display Representation describes the type as a whole, and a caseDisplayRepresentation describes each case of the enum.

    These representations must be constant values, since this information is used at compile time.

    In my intent, I’ll add a new variable to hold the Navigation Option.

    I’ll add the @Parameter attribute to make this into an intent parameter. Intent parameters act as inputs to intents.

    They can be required or optional. I’ve made this required, so the runtime will ensure it has a value before perform is called.

    I’ll update the perform method to use the resolved Navigation Option and change the title to reflect the new action.

    Going back into my Shortcut, I’ll now see Navigation Option as an editable parameter. When I run the intent, Shortcuts will prompt for the section.

    I’ll choose Map, and be opened directly to that view. Types from the App Intents framework are designed to be highly customizable. This lets you quickly get the building blocks in place and then refine the experience. I’ll add some additional information to the intent, making it even better to use.

    By default, Shortcuts will show each parameter as a row. Tapping the row will bring up a list of values for that type. This works, but there are a few things I can do to refine the experience.

    An App Enum only requires a title for each enum case but can be configured with additional information, such as an icon.

    To add an icon, I’ll need to use the Display Representation initializer.

    I can then add a symbol for each case.

    Once I do that, Shortcuts will display the image in the picker. Intents can be configured with a fluent, sentence-like representation, called a Parameter Summary.

    A Parameter Summary describes the action and its parameters in a human-readable way.

    I’ll provide the summary with my parameter interpolated into the string. Shortcuts will display the summary with the selectable parameter inline, providing a more useful description of the action.

    Actually, this doesn’t quite read like a sentence yet.

    I can fix that by adding a custom title to my parameter.

    While I’m here, I’ll also add a custom dialog to show when requesting a value.

    New this year, when you implement a Parameter Summary for your intent that includes all required parameters, people will be able to run your action from Spotlight on the Mac. To learn more about new additions to Spotlight, I encourage you to watch this session.

    Modeling your app’s actions as intents lets your customers build powerful shortcuts and automations. However, some intents are so central to your app that they should be available the moment your app is installed. You can provide these by adopting App Shortcuts.

    An App Shortcut is a type that automatically exposes an App Intent across the system. App Shortcuts are featured prominently when searching in Spotlight. People can use Siri to run an App Shortcut by speaking one of their trigger phrases.

    They can be configured to run from the Action Button or Apple Pencil squeeze.

    App Shortcuts will show in the Shortcuts app without any user setup and the best part - they only take a couple lines of code to build. Let’s check out how.

    Apps provide App Shortcuts through an App Shortcuts Provider. Your app should define a single provider, containing all your App Shortcuts.

    An App Shortcut takes an instance of an intent as well as a list of phrases, a title, and an image.

    An App Shortcut’s phrases can be uttered or typed to Siri, to run the App Shortcut.

    Each phrase must include the applicationName placeholder. Phrases can include up to one intent parameter. If provided, an App Shortcut for each value of that type will be created.

    This simple structure's all that’s required to create an App Shortcut. Shortcuts will show your app’s App Shortcuts in a new section. The phrases influence the App Shortcuts that are created. Supplying a phrase without a parameter will create an App Shortcut using the title and image name.

    Since I’ve supplied a phrase with an App Enum, an App Shortcut for each case will be created.

    I can now run my intent with Siri or Spotlight. App Shortcuts are a great way to make your intents discoverable.

    To learn more about building App Shortcuts, see this session from WWDC23.

    Landmarks are a core concept in my app. It would be great to take action on them from my intents. Unlike the constant list of navigation options, landmarks are dynamic, so I can’t use an App Enum. I’ll instead make an App Entity to model my landmarks.

    My app already has a Landmark type. While I could conform that type to App Entity, in this case, I’m going to create a new LandmarkEntity struct. This type will act as a bridge between App Intents and my underlying data model.

    App Entities must be identifiable, so I’ll add an ID. It’s important that this identifier is persistent and that you are able to lookup instances of your entity by this ID. We’ll come back to this. Similar to an intent having parameters, entities can have properties denoted with the @Property attribute. These will be exposed to your customers in Shortcuts and can be used in Find and Filter actions.

    I could set these values from my data model, but new this year, I can add Getters to my entity properties, using the new @ComputedProperty attribute. Instead of copying values between these types, I can defer to my data model.

    Similar to App Enums, App Entities require a representation for the type and instances of the type.

    App Entities require one additional piece of information, known as a query.

    Unlike an App Enum that has a known set of values, App Entities are dynamic. My app can have any number of landmarks.

    Queries are the way the system can reason about my entities. It does this by answering a number of different questions. The first type of question is, “What entities are there?" The query is responsible for answering that question and returning a collection of matching entities.

    Queries support many types of this question. For example, an Entity String Query asks the question, “Do you have any entities matching this string?” An Entity Property Query might ask, “What are all the landmarks from this state?” All queries must answer one very specific question, “What is the entity for this ID?” This allows the system to uniquely reference an entity and only resolve it when it’s needed.

    I can provide the query by creating a type that conforms to the Entity Query protocol.

    The entities(for:) method is how queries answer the, “What entity has this ID?" question. It takes an array of identifiers and returns an array of entity instances. We’ll come back to the, “What entities are there?" question later. Queries often need access to a local database or other dependency to fetch instances.

    I can use the @Dependency attribute to inject dependencies into my query. I’ll need to register my dependency using the shared App Dependency Manager. You should register dependencies as early as possible in your app’s lifecycle. Now that I’ve created a Landmark App Entity, I can use it from my intents. When traveling, it would be great to know what my closest landmark is. I’ll make an App Intent to show me. I’ll start with a basic Closest Landmark intent.

    I’ll need to fetch my closest landmark from my data model. Dependencies are also supported in intents, so I can add my dependency.

    For my perform method, I’ll add a ReturnsValue of Landmark Entity.

    Types used as intent parameters can also be returned from an intent. A returned value can be used as an input to another intent, such as in a multi-step Shortcut. I’ll also return a dialog and a view snippet. This lets my intent show or speak the result of my intent.

    Lastly, I can implement my perform method.

    After finding the closest landmark, I’ll return a result containing the entity, dialog, and view. By providing both a dialog and view, I’ll ensure my customers can always find their closest landmark no matter how the intent was invoked. Speaking of, making an App Shortcut for this intent will make running this intent even easier.

    My customers can now use Siri or Spotlight to have convenient access to this intent even if their phone is in their pocket. Intents, entities, and queries are the building blocks of App Intents. Each protocol has sub-protocols and configurations that you can use to provide additional functionality. Let’s check out how I can refine my App Entity, to provide additional experiences.

    I’d like to easily be able to see a photo of my nearest landmark. I can use the Shortcuts app to help me. I’ll start by creating a Shortcut and adding the Find Closest Landmark intent. To checkout the results, I’ll add a Show Content action. This will take the result of my intent and render it. By default, this action will show the display representation of the Landmark entity, but I can choose any entity property to render.

    Landmark entity doesn’t hold an image directly, but it does have a path to the image. I can use the Transferable protocol to declare an image representation for the entity. Transferable is a declarative way to describe different data representations for a type. These representations can be used to share data between apps. I’ll provide the image data as part of the type’s Transfer Representation. Back in Shortcuts, I can now choose to show the image representation of the entity.

    Running my shortcut will show the landmark’s image. Declaring an image representation has additional benefits. I can use this image value as an input to any action that takes a photo, even those from other apps.

    To learn more about Transferable, check out these sessions.

    I’d like to make one more change to my entity to make it easier to find in the system. Spotlight provides powerful semantic search across applications. Donating entities to Spotlight extends the system’s understanding of your content. To have Spotlight index my entity, I can adopt the Indexed Entity protocol.

    An Indexed Entity is an App Entity that includes a Core Spotlight attribute set.

    New this year, you can now add Spotlight indexing keys directly on properties. Annotating properties allows Spotlight to show more relevant information to customers. When donating indexed entities, the framework will handle creating the searchable item and attribute set for you. After donating entities, they can be found in Spotlight.

    By default, tapping an entity will foreground the app. I can make this experience even better and open directly to the landmark detail view.

    I’ll start by creating an intent conforming to the Open Intent protocol.

    Intents adopting this protocol will automatically open the app before they’re performed, so I can skip adding a supported mode. Open Intents must have a target parameter. When tapping an entity in Spotlight, it will run a matching Open Intent, if one exists.

    Instead of calling out to my navigator, I can now adopt the new Target Content Providing Intent protocol, designed specifically for navigation. These intents do not require a perform method.

    Instead, I can attach an onAppIntentExecution modifier to my view. In the closure, I can use the intent’s parameter to perform a SwiftUI navigation.

    Now, when tapping a landmark from Spotlight, I’ll navigate directly to the landmark detail view.

    I’d like to wrap up this section by talking a bit more about queries and how they provide entities. To check out this in action, I’ll create a new App Shortcut for opening a landmark. I’ve added a new App Shortcut to my provider along with two phrases. One with a landmark parameter and one without.

    However, running my App Shortcut doesn’t give me any landmarks to choose. As you might have guessed, I can use the query to provide some landmarks. I’ll implement the optional suggestedEntities method on Entity Query, returning my customer’s favorite landmarks. Now, when running the intent again, I’m presented with the list of suggested entities. Suggested entities have another use as well.

    Remember when I added a parameterized phrase for this intent. I can generate an App Shortcut for each suggested entity by calling the updateAppShortcutParameters method on my provider.

    I can now use Siri and Shortcuts to easily navigate directly to my favorite landmarks. Queries can answer a number of other questions about your entities.

    If your entities can all fit in memory, you can use an Enumerable Entity Query to return them all. App Intents can derive the more complicated queries from this one. An Entity Property Query adds the ability to return a sorted list of entities, given a set of predicates. In my case, I’ll implement an Entity String Query to support finding entities from a string.

    I’ll return a list of landmarks where the string matches their name or description. Customers will now be able to search all landmarks when configuring an intent that needs a landmark. We only scratched the surface of the App Intents framework and its many capabilities. Check out the App Intents documentation to see all the ways you can use the framework to delight your users.

    I’d like to end by providing insight into the architecture powering App Intents.

    When building your app with App Intents, your code is the source of truth.

    App Intents doesn’t require any setup or configuration files. Your Swift source code will be read at build time to generate its App Intents representation. This representation is stored inside your app or framework. After your app is installed, the system will use this data to understand your app’s capabilities without needing to run your app. Let’s take a look at an intent to see how this works. The name of the intent becomes the unique identifier of the action. An intent’s title helps users differentiate between intents, and the perform method’s return signature describes how to render the result of the intent.

    Since this process happens at build time, rather than at run time, certain values must be provided with constant values. For example, an intent’s title must be constant. Calling out to a function or computed property will result in an error. This processing happens individually for each target in your app. In order to properly share your App Intent types between targets, there are a few additional things to be aware of. Last year, we introduced the ability for your app and App Intents extensions to reference App Intent types defined in a framework. This year, we’re excited to announce that you can now add App Intents to your Swift packages and static libraries. When using App Intent types across targets, you must provide the runtime with additional information about each target. This ensures that your types are properly indexed and validated. Let’s dive in to check out how that’s done. My app only has a single target containing all my App Intents code. I want to introduce a new App Intents extension to host some of my intents. Both targets will need access to Landmarks. So, I’ll create a Swift package and move my Landmark entity to it.

    To share types between targets, I’ll need to register each target as an App Intents Package. First, I’ll create an App Intents Package in the same target as the entity.

    I’ll add another App Intents Package to my app target. I can supply a list of included packages, so I’ll include the one I just created. Finally, I’ll do the same from my extension. This will ensure the App Intents runtime has proper access to all types defined in the package. You should use App Intents Package when referencing code not compiled into a static library.

    Time to wrap this talk up. If this was your first look at App Intents, start small by adding the first App Shortcut to your app. From there, explore the framework to checkout which of its capabilities can bring the most value to your customers. For more about App Intents, we have some other great sessions this year. Thanks for watching!

    • 3:23 - Navigate Intent

      struct NavigateIntent: AppIntent {
          static let title: LocalizedStringResource = "Navigate to Landmarks"
      
          static let supportedModes: IntentModes = .foreground
      
          @MainActor
          func perform() async throws -> some IntentResult {
              Navigator.shared.navigate(to: .landmarks)
              return .result()
          }
      }
    • 5:02 - Navigation Option App Enum

      enum NavigationOption: String, AppEnum {
          case landmarks
          case map
          case collections
      
          static let typeDisplayRepresentation: TypeDisplayRepresentation = "Navigation Option"
      
          static let caseDisplayRepresentations: [NavigationOption: DisplayRepresentation] = [
              .landmarks: "Landmarks",
              .map: "Map",
              .collections: "Collections"
          ]
      }
    • 5:38 - Navigate Intent with Parameter

      struct NavigateIntent: AppIntent {
          static let title: LocalizedStringResource = "Navigate to Section"
      
          static let supportedModes: IntentModes = .foreground
        
          @Parameter var navigationOption: NavigationOption
      
          @MainActor
          func perform() async throws -> some IntentResult {
              Navigator.shared.navigate(to: navigationOption)
              return .result()
          }
      }
    • 6:57 - Case Display Representations with Images

      static let caseDisplayRepresentations = [
          NavigationOption.landmarks: DisplayRepresentation(
              title: "Landmarks",
              image: .init(systemName: "building.columns")
          ),
          NavigationOption.map: DisplayRepresentation(
              title: "Map",
              image: .init(systemName: "map")
          ),
          NavigationOption.collections: DisplayRepresentation(
              title: "Collections",
              image: .init(systemName: "book.closed")
          )
      ]
    • 7:28 - Navigation Option With Parameter Summary

      struct NavigateIntent: AppIntent {
          static let title: LocalizedStringResource = "Navigate to Section"
      
          static let supportedModes: IntentModes = .foreground
        
          static var parameterSummary: some ParameterSummary {
              Summary("Navigate to \(\.$navigationOption)")
          }
        
          @Parameter(
              title: "Section",
              requestValueDialog: "Which section?"
          )
          var navigationOption: NavigationOption
      
          @MainActor
          func perform() async throws -> some IntentResult {
              Navigator.shared.navigate(to: navigationOption)
              return .result()
          }
      }
    • 9:22 - App Shortcuts Provider and Navigation Intent App Shortcut

      struct TravelTrackingAppShortcuts: AppShortcutsProvider {
          static var appShortcuts: [AppShortcut] {
              AppShortcut(
                  intent: NavigateIntent(),
                  phrases: [
                      "Navigate in \(.applicationName)",
                      "Navigate to \(\.$navigationOption) in \(.applicationName)"a
                  ],                
                  shortTitle: "Navigate",
                  systemImageName: "arrowshape.forward"
              )
          }
      }
    • 11:02 - Landmark Entity

      struct LandmarkEntity: AppEntity {
          var id: Int { landmark.id }
      
          @ComputedProperty
          var name: String { landmark.name }
      
          @ComputedProperty
          var description: String { landmark.description }
        
          let landmark: Landmark
        
          static let typeDisplayRepresentation = TypeDisplayRepresentation(name: "Landmark")
      
          var displayRepresentation: DisplayRepresentation {
              DisplayRepresentation(title: "\(name)")
          }
        
          static let defaultQuery = LandmarkEntityQuery()
      }
    • 13:19 - Landmark Entity Query

      struct LandmarkEntityQuery: EntityQuery {
          @Dependency var modelData: ModelData
        
          func entities(for identifiers: [LandmarkEntity.ID]) async throws -> [LandmarkEntity] {
              modelData
                  .landmarks(for: identifiers)
                  .map(LandmarkEntity.init)
          }
      }
    • 13:50 - App Dependency Manager

      @main
      struct LandmarksApp: App {    
          init() {
              AppDependencyManager.shared.add { ModelData() }
          }
      }
    • 14:18 - Closest Landmark Intent

      struct ClosestLandmarkIntent: AppIntent {
          static let title: LocalizedStringResource = "Find Closest Landmark"
      
          @Dependency var modelData: ModelData
      
          @MainActor
          func perform() async throws 
              -> some ReturnsValue<LandmarkEntity> & ProvidesDialog & ShowsSnippetView {
              
              let landmark = try await modelData.findClosestLandmark()
      
              return .result(
                  value: landmark,
                  dialog: "The closest landmark to you is \(landmark.name)",
                  view: ClosestLandmarkView(landmark: landmark)
              )
          }
      }
    • 15:18 - Closest Landmark App Shortcut

      AppShortcut(
          intent: ClosestLandmarkIntent(),
          phrases: [
              "Find closest landmark in \(.applicationName)"
          ],
          shortTitle: "Closest landmark",
          systemImageName: "location"
      )
    • 16:33 - Transferable

      extension LandmarkEntity: Transferable {
          static var transferRepresentation: some TransferRepresentation {
              DataRepresentation(exportedContentType: .image) {
                  return try $0.imageRepresentationData
              }
          }
      }
    • 17:31 - Indexed Entity

      struct LandmarkEntity: IndexedEntity {
          // ...
          
          @Property(
              indexingKey: \.displayName
          )
          var name: String
      
          @Property(
              indexingKey: \.contentDescription
          )
          var description: String
      }
    • 18:17 - Open Landmark Intent

      struct OpenLandmarkIntent: OpenIntent, TargetContentProvidingIntent {
          static let title: LocalizedStringResource = "Open Landmark"
      
          @Parameter(title: "Landmark", requestValueDialog: "Which landmark?")
          var target: LandmarkEntity
      }
      
      struct LandmarksNavigationStack: View {
          @State var path: [Landmark] = []
      
          var body: some View {
              NavigationStack(path: $path) {}
              .onAppIntentExecution(OpenLandmarkIntent.self) { intent in
                  path.append(intent.target.landmark)
              }
          }
      }
    • 19:24 - Open Landmark App Shortcut

      AppShortcut(
          intent: OpenLandmarkIntent(),
          phrases: [
              "Open \(\.$target) in \(.applicationName)",
              "Open landmark in \(.applicationName)"
          ],
          shortTitle: "Open",
          systemImageName: "building.columns"
      )
    • 19:39 - Suggested Entities

      struct LandmarkEntityQuery: EntityQuery {
          // ...
      
          func suggestedEntities() async throws -> [LandmarkEntity] {
              modelData
                  .favoriteLandmarks()
                  .map(LandmarkEntity.init)
          }
      }
    • 20:06 - Update App Shortcut Parameters

      TravelTrackingAppShortcuts.updateAppShortcutParameters()
    • 20:25 - EnumerableEntityQuery

      extension LandmarkEntityQuery: EnumerableEntityQuery {
          func allEntities() async throws -> [LandmarkEntity] { 
              // ...
          }
      }
    • 20:36 - EntityPropertyQuery

      extension LandmarkEntityQuery: EntityPropertyQuery {
          static var properties = QueryProperties {
              // ...
          }
      
          static var sortingOptions = SortingOptions {
              // ...
          }
      
          func entities(
              matching comparators: [Predicate<LandmarkEntity>],
              mode: ComparatorMode,
              sortedBy: [Sort<LandmarkEntity>],
              limit: Int?
          ) async throws -> [LandmarkEntity] {
              // ...
          }
      }
    • 20:44 - EntityStringQuery

      extension LandmarkEntityQuery: EntityStringQuery {
          func entities(matching: String) async throws -> [LandmarkEntity] {
              modelData
                  .landmarks
                  .filter { $0.name.contains(matching) || $0.description.contains(matching) }
                  .map(LandmarkEntity.init)
          }
      }
    • 23:10 - App Intents Package

      // TravelTrackingKit
      public struct TravelTrackingKitPackage: AppIntentsPackage {}
      public structaLandmarkEntity: AppEntity {}
      
      // TravelTracking
      struct TravelTrackingPackage: AppIntentsPackage {
          static var includedPackages: [any AppIntentsPackage.Type] {
              [TravelTrackingKitPackage.self]
          }
      }
      struct OpenLandmarkIntent: OpenIntent {}
      
      // TravelTrackingAppIntentsExtension
      struct TravelTrackingExtensionPackage: AppIntentsPackage {
          static var includedPackages: [any AppIntentsPackage.Type] {
              [TravelTrackingKitPackage.self]
          }
      }
      struct FavoriteLandmarkIntent: AppIntent {}
    • 0:00 - Introduction
    • Learn about App Intents — a framework you can use to enhance app discoverability and functionality across all Apple platforms. Topics include the framework's importance, implementation, and best practices for writing App Intents.

    • 0:45 - App Intents ecosystem
    • App Intents is an ecosystem that enables apps to extend functionality across the system — Spotlight, Action Button, Widgets, Control Center, and Apple Pencil Pro. People can perform app actions from anywhere, even when not in the app. You define app actions as intents, which can take parameters and return values using App Enums for constants, or App Entities for dynamic types. App Shortcuts, built from intents and parameters, enhance accessibility and discoverability through Spotlight, Siri, and the Action Button.

    • 2:47 - Navigating the framework
    • The example app explores famous landmarks worldwide. To enhance user experience, it implements App Intents, which allow people to perform actions directly from Siri, Shortcuts, and Spotlight. The process involves defining structs that adopt the App Intents protocol, specifying titles, perform methods, and intent results. You add parameters to the intents, enabling people to choose specific sections of the app, such as the landmarks grid or map view. To make the app more discoverable and user-friendly, you create App Shortcuts, which automatically expose intents across the system. They also model dynamic data like landmarks using App Entities, allowing people to take actions on specific landmarks through intents. In the App Intents framework, App Entities represent dynamic data such as landmarks. Queries are essential components that enable the system to reason about these entities. They answer various questions, including retrieving all entities, matching specific strings or properties, and uniquely referencing entities by ID. You can customize queries using different types, such as Entity String Query and Entity Property Query, and these queries may depend on local databases or other resources. Dependencies can be injected into queries using the '@Dependency' attribute. Register dependencies as early as possible in the app life cycle. Using App Intents, you can create custom actions that can be performed using Siri, Spotlight, or Shortcuts. By returning entity types from intents, these actions can be chained together in multi-step shortcuts. To enhance the user experience, you can make entities transferable, allowing them to be shared between apps. Adopting the Indexed Entity protocol enables Spotlight for semantic search. You can also create Open Intents to directly navigate to specific views within the app when entities are tapped in Spotlight.

    • 21:15 - How it works
    • App Intents uses Swift source code at build time to generate an App Intents representation, which is then stored within the app or framework. This allows the system to understand the app's capabilities without running it. The intent's name serves as its unique identifier; the title helps people differentiate between intents, and the 'perform' method's return signature defines how to render the result. You need to provide constant values for certain intent properties because processing occurs at build time. To share App Intent types between targets, such as an app and its extension, you can use Swift packages or static libraries. You must register each target as an App Intents Package to ensure proper indexing and validation of the shared types by the App Intents runtime.

Developer Footer

  • 视频
  • WWDC25
  • 了解 App Intents
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则