-
Découvrez de nouvelles capacités dans le framework App Intents
Optimisez l'intégration de vos App Intents grâce à des fonctionnalités avancées pour la rendre plus rapide, plus flexible et plus pertinente. Valorisez votre contenu en le rendant plus accessible et mobile d'une app à l'autre grâce à ValueRepresentation et RelevantEntities, boostez vos performances avec EntityCollection et déployez votre app sur plusieurs appareils grâce à SyncableEntity. Explorez des types de paramètres plus riches, notamment les valeurs d'union et les intents de longue durée qui gèrent l'annulation de manière élégante.
Chapitres
- 0:00 - Introduction
- 2:40 - Share entities across apps with ValueRepresentation
- 3:45 - Register relevant entities with RelevantEntities
- 7:05 - Handle entities efficiently with EntityCollection
- 8:55 - Use entities across devices with SyncableEntity
- 11:01 - Richer parameter types
- 12:38 - Union value parameters
- 13:26 - Extend execution with LongRunningIntent
- 15:27 - Target the right process with ExecutionTargets
- 17:14 - Next steps
Ressources
-
Rechercher dans cette vidéo…
-
-
0:01 - Share structured entities with ValueRepresentation
struct LandmarkEntity: AppEntity, Transferable { var id: Int var landmark: Landmark // contains CLLocationCoordinate2D static var transferRepresentation: some TransferRepresentation { ValueRepresentation( exporting: { entity in PlaceDescriptor( representations: [.coordinate(entity.landmark.locationCoordinate)], commonName: entity.landmark.name ) } ) } } // If the entity already has a PlaceDescriptor property, use a key-path — much less code: struct LandmarkEntity: AppEntity, Transferable { var id: Int @Property var placeDescriptor: PlaceDescriptor static var transferRepresentation: some TransferRepresentation { ValueRepresentation(exporting: \.placeDescriptor) } } -
5:18 - Register relevant entities with RelevantEntities
// Suggest playlists for the workout session let playlistEntities = [dailyRun, runningMix] let workoutContext = AppEntityContext.audio(.workout(activityType: .running)) try await RelevantEntities.shared.updateEntities( playlistEntities, for: workoutContext ) // Clear all entities for a context try await RelevantEntities.shared.removeAllEntities(for: workoutContext) // Remove specific entities from a context try await RelevantEntities.shared.removeEntities(playlistEntities, from: workoutContext) // Or remove all entities across all contexts try await RelevantEntities.shared.removeAllEntities() -
7:15 - Handle large entity sets with EntityCollection
struct TagPhotosIntent: AppIntent { static let title: LocalizedStringResource = "Tag Travel Photos" @Parameter var photos: EntityCollection<PhotoEntity> // was: [PhotoEntity] @Parameter var tag: String func perform() async throws -> some IntentResult { modelData.tagPhotos(ids: photos.identifiers, tag: tag) // was: tagPhotos(photos, tag: tag) return .result() } } -
10:14 - Make entity IDs stable with SyncableEntity
// If your ID is already stable across devices (server UUID, CloudKit record ID): struct PhotoEntity: AppEntity, SyncableEntity { var id: Int // Already stable across devices — that's it } // If you use local IDs, pair a local and a stable ID: struct PhotoEntity: AppEntity, SyncableEntity { var id: SyncableEntityIdentifier<String, String> init(localID: String, stableID: String) { self.id = SyncableEntityIdentifier(local: localID, stable: stableID) } } -
11:58 - Accept multiple types with @UnionValue
@UnionValue enum TravelGalleryContent { case landmarkCollection(LandmarkCollectionEntity) case photoAlbum(PhotoAlbumEntity) static let typeDisplayRepresentation: TypeDisplayRepresentation = "Travel Gallery" static let caseDisplayRepresentations: [Cases: DisplayRepresentation] = [ .landmarkCollection: "Landmark Collection", .photoAlbum: "Photo Album" ] } -
13:41 - Run beyond 30 s with LongRunningIntent + CancellableIntent
struct UploadPhotoIntent: LongRunningIntent, CancellableIntent { static let title: LocalizedStringResource = "Upload Photo" @Parameter var photo: IntentFile func perform() async throws -> some IntentResult & ProvidesDialog { let result = try await performBackgroundTask { let chunks = calculateChunks(for: photo) progress.totalUnitCount = Int64(chunks) for chunk in 1...chunks { try Task.checkCancellation() try await uploadChunk(chunk) progress.completedUnitCount = Int64(chunk) } return "Upload complete!" } onCancel: { reason in cleanup(for: reason) } return .result(dialog: "\(result)") } } -
16:54 - Control which process runs your intent with ExecutionTargets
// Write operation — needs the main app struct UpdateFavoriteIntent: AppIntent { static var allowedExecutionTargets: ExecutionTargets { .main } } // Standalone download — runs in the extension struct DownloadPhotoIntent: AppIntent { static var allowedExecutionTargets: ExecutionTargets { .appIntentsExtension } } // Display-only — runs in the widget extension struct GetLandmarkStatusIntent: AppIntent { static var allowedExecutionTargets: ExecutionTargets { .widgetKitExtension } } // Works in either — lets the system choose struct TagPhotosIntent: AppIntent { static var allowedExecutionTargets: ExecutionTargets { [.main, .appIntentsExtension] } }
-
-
- 0:00 - Introduction
The 2027 App Intents updates — more control, flexibility, and a smoother developer experience across Siri, Shortcuts, Spotlight, Widgets, and Apple Intelligence. Three areas: entity enhancements, richer parameters, and intent execution, built on the Landmarks Travel Tracking sample.
- 2:40 - Share entities across apps with ValueRepresentation
Beyond Transferable's File and Data representations, the new ValueRepresentation shares structured types the system understands, for example exporting a landmark as a PlaceDescriptor (GeoToolbox) so it flows to Maps for directions. Use a key-path if the entity already has the property.
- 3:45 - Register relevant entities with RelevantEntities
Spotlight indexing and interaction donation can't surface never-seen, never-used content. RelevantEntities lets you suggest entities with a context (such as running playlists when a workout starts) via updateEntities, and remove them by context, by entity, or entirely.
- 7:05 - Handle entities efficiently with EntityCollection
Resolving every entity before an intent runs is costly at scale (tagging thousands of photos). EntityCollection passes just identifiers to perform() without full resolution, a one-line parameter-type change that made tagging 1000 photos nearly instant.
- 8:55 - Use entities across devices with SyncableEntity
Siri conversations now continue across devices, but local IDs differ per device. SyncableEntity declares a stable ID (server UUID or CloudKit record ID); when you only have local IDs, SyncableEntityIdentifier pairs a local and a stable ID so on-device code uses local and the system uses stable.
- 11:01 - Richer parameter types
Declaring a @Parameter gives a native picker, Siri understanding, and localization for free, now extended to more native types like Duration (no custom time pickers) and PersonNameComponents, working across Siri, Shortcuts, and Widgets.
- 12:38 - Union value parameters
A @UnionValue enum lets one parameter accept multiple types, for example a single widget showing photos from either a landmark collection or a photo album. The macro generates type info, case metadata, and picker support (typeDisplayRepresentation, caseDisplayRepresentations), and works everywhere including Shortcuts.
- 13:26 - Extend execution with LongRunningIntent
Intents normally have 30 seconds; LongRunningIntent runs beyond it, manages the background task lifecycle, and shows progress as a Live Activity. Wrap work in performBackgroundTask and report progress (it builds on ProgressReportingIntent). Add CancellableIntent's onCancel to clean up gracefully; it also supports background GPU access.
- 15:27 - Target the right process with ExecutionTargets
When intents live in a shared package linked by the app and extensions, the system picks a process by heuristics, not always right (for example a widget favorite button needs the writing main app). ExecutionTargets overrides this to target the main app, an App Intents extension, a WidgetKit extension, or any combination.
- 17:14 - Next steps
Add ValueRepresentation to carry structured data, register relevant content, adopt EntityCollection for large entity sets, and add LongRunningIntent for work over 30 seconds. See "Code-along: Make your app available to Siri" and "Validate your App Intents adoption with AppIntentsTesting."