View in English

  • Apple Developer
    • 시작하기

    시작하기 탐색

    • 개요
    • 알아보기
    • Apple Developer Program

    알림 받기

    • 최신 뉴스
    • Hello Developer
    • 플랫폼

    플랫폼 탐색

    • Apple 플랫폼
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    피처링

    • 디자인
    • 배포
    • 게임
    • 액세서리
    • 웹
    • 홈
    • CarPlay
    • 기술

    기술 탐색

    • 개요
    • Xcode
    • Swift
    • SwiftUI

    피처링

    • 손쉬운 사용
    • 앱 인텐트
    • Apple Intelligence
    • 게임
    • 머신 러닝 및 AI
    • 보안
    • Xcode Cloud
    • 커뮤니티

    커뮤니티 탐색

    • 개요
    • Apple과의 만남 이벤트
    • 커뮤니티 주도 이벤트
    • 개발자 포럼
    • 오픈 소스

    피처링

    • WWDC
    • Swift Student Challenge
    • 개발자 이야기
    • App Store 어워드
    • Apple 디자인 어워드
    • 문서

    문서 탐색

    • 문서 라이브러리
    • 기술 개요
    • 샘플 코드
    • 휴먼 인터페이스 가이드라인
    • 비디오

    릴리즈 노트

    • 피처링 업데이트
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • 다운로드

    다운로드 탐색

    • 모든 다운로드
    • 운영 체제
    • 애플리케이션
    • 디자인 리소스

    피처링

    • Xcode
    • TestFlight
    • 서체
    • SF Symbols
    • Icon Composer
    • 지원

    지원 탐색

    • 개요
    • 도움말
    • 개발자 포럼
    • 피드백 지원
    • 문의하기

    피처링

    • 계정 도움말
    • 앱 심사 지침
    • App Store Connect 도움말
    • 새로 추가될 요구 사항
    • 계약 및 지침
    • 시스템 상태
  • 빠른 링크

    • 이벤트
    • 뉴스
    • 포럼
    • 샘플 코드
    • 비디오
 

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 전체 비디오
  • 소개

더 많은 비디오

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • App Intents 프레임워크의 새로운 기능 살펴보기

    고급 기능으로 앱 인텐트 도입을 레벨업하여 속도, 유연성, 관련성을 향상해 보세요. ValueRepresentation과 RelevantEntities가 콘텐츠의 검색 가능성을 높이고 앱 간 이동을 가능하게 하며, EntityCollection이 성능을 향상하고, SyncableEntity를 통해 여러 기기 간에 확장할 수 있는 방법을 알아보세요. union 값과 취소를 원활하게 처리하는 장기 실행 인텐트를 포함한 더 풍부한 매개변수 유형을 살펴보세요.

    챕터

    • 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

    리소스

    • Adopting App Intents to support system experiences
    • App Intents
      • HD 비디오
      • SD 비디오
  • 비디오 검색…

    안녕하세요, 저는 Moe입니다 App Intents 팀의 엔지니어예요 2027 릴리스에서 소개할 새로운 App Intents 기능을 여러분과 함께 나눌 수 있어서 기쁩니다 App Intents는 앱의 액션과 콘텐츠를 시스템의 다른 부분에 자연스럽고 깊게 통합된 방식으로 전달하는 프레임워크입니다 Siri와 Shortcuts 앱부터 Spotlight와 Widget까지 App Intents는 핵심 엔진으로 Apple 플랫폼에서 가장 훌륭한 경험들을 구동해 왔습니다 이제 Apple Intelligence의 핵심 축이 되었습니다 2027 릴리스에서는 여러분의 기능 요청에 따라 더 많은 제어, 더 많은 유연성 그리고 훨씬 매끄러운 개발자 경험을 제공합니다 오늘은 세 가지 영역을 살펴보겠습니다 먼저 엔티티부터 시작하겠습니다 앱 간에 공유하는 새로운 방법 관련성 시점을 시스템에 알리는 방법 대규모 처리 방법을 보여드릴게요 그런 다음, 기본 타입의 새로운 지원을 안내하고 완전한 Shortcuts 통합을 갖춘 유니온 값을 소개합니다 마지막으로, 인텐트가 더 오래 실행되고 취소를 원활히 처리하며 올바른 프로세스에서 실행되는 방법을 보여드릴게요 오늘은 새 기능에 집중하겠습니다 App Intents가 처음이거나 기본 개념을 복습하고 싶다면 WWDC25의 "Get to know App Intents"를 확인해 보세요 해당 영상에서는 Landmarks Travel Tracking 앱을 소개합니다 오늘 다루는 API를 활용해 이 앱을 발전시켜 나가겠습니다 샘플 코드를 다운로드해서 함께 따라오실 수 있습니다 새로운 기능을 살펴보겠습니다 여러분의 엔티티, 즉 앱의 콘텐츠는 랜드마크나 재생 목록처럼 앱 안에 있습니다 하지만 앱 사용자는 그렇지 않죠 사람들은 늘 앱 사이를 이동합니다 Mail과 Maps를 여행 추적 앱과 함께 사용하는 예시를 살펴보겠습니다 친구와 여행 아이디어를 공유하는 단축어를 만들었습니다 근처 랜드마크를 찾아서 메시지와 함께 보내는 단축어예요 제 엔티티는 CoreTransferable 프레임워크의 Transferable을 준수하므로 단축어가 Mail이 사용할 수 있는 형식으로 공유할 수 있습니다 이건 잘 작동합니다 하지만 친구에게 보내는 대신 그 랜드마크로 길 안내를 받고 싶다면 어떨까요? 그건 동작하지 않습니다 Maps에는 좌표, 주소 같은 구조화된 정보가 필요합니다 또는 내비게이션이 가능한 무언가요 하지만 그런 데이터에는 연관된 데이터 형식이 없습니다 파일이나 데이터로 저장할 수 있는 기존의 파일 및 데이터 표현은 PDF나 이미지 같은 알려진 형식에는 잘 작동하지만 형식이 없는 구조화된 타입에는 적합하지 않습니다 바로 이때 ValueRepresentation이 필요합니다 시스템이 이미 이해하는 구조화된 타입을 공유할 수 있는 새로운 표현 타입입니다 제 LandmarkEntity는 여행 추적 앱의 장소를 나타냅니다 이미 Transferable을 준수하므로 기존 표현들과 함께 ValueRepresentation만 추가하면 됩니다 ValueRepresentation 안에서 랜드마크의 좌표와 이름을 GeoToolbox 프레임워크의 PlaceDescriptor로 내보냅니다 PlaceDescriptor는 좌표와 기타 메타데이터를 담고 있어 Maps가 내비게이션하는 데 필요합니다 엔티티에 이미 PlaceDescriptor @Property가 있다면 클로저를 생략하고 키 패스를 사용할 수 있습니다 결과는 같지만 코드는 훨씬 줄어들죠

    단축어로 돌아가서 실행을 탭하면 랜드마크가 PlaceDescriptor로 Maps에 전달되고 Maps가 랜드마크로 길 안내 화면을 열어줍니다

    이제 엔티티가 앱 간에 이동하는 방법이 더 다양해졌습니다 이제 시스템이 관련성이 있을 때 제안하도록 도와주는 방법을 알아봅니다 CosmoTunes 같은 음악 앱을 만든다고 가정해 보세요 이 영상의 샘플 앱인 "Explore advanced App Intents features for Siri and Apple Intelligence"에서요 앱에 빠른 템포의 새 재생 목록이 생겼고 달리기에 딱 맞습니다 누군가 Fitness 앱에서 달리기 운동을 설정하면 추천 재생 목록 목록이 표시됩니다 내 재생 목록을 그 추천에 어떻게 포함할 수 있을까요?

    현재 콘텐츠를 시스템에 제공하는 두 가지 방법이 있습니다 첫 번째는 Spotlight에 콘텐츠를 인덱싱하는 방법입니다 이렇게 하면 사람들이 콘텐츠를 검색할 수 있게 됩니다 시맨틱 검색을 포함한 Spotlight UI에서요 Siri가 콘텐츠를 가져오는 주요 방법이기도 합니다 두 번째는 인터랙션 기부입니다 사람들이 앱에서 액션을 취하면 IntentDonationManager API를 통해 해당 인터랙션을 시스템에 기부합니다 시스템은 시간이 지나면서 패턴을 학습하고 나중에 유사한 액션을 제안할 수 있습니다 Siri는 이러한 인터랙션을 사용해 더 개인화된 경험을 제공하기도 합니다 그런데 새 재생 목록은 어떻게 될까요? 존재를 모르니까 Spotlight에서 검색하는 사람이 없죠 아무도 재생하지 않았으니 기부할 인터랙션도 없습니다 이 재생 목록이 관련성이 있다는 것을 시스템에 알려야 합니다 올바른 순간에 표시될 수 있도록요 RelevantEntities를 소개합니다 RelevantEntities를 사용하면 시스템에 엔티티를 제안하고 언제, 왜 관련성이 있는지 컨텍스트를 제공할 수 있습니다 작동 방법을 살펴볼게요 먼저 관련 엔티티를 파악합니다 이 경우에는 달리기 재생 목록들이죠 그런 다음 시스템에 알릴 컨텍스트를 생성합니다 이 재생 목록들은 달리기를 시작할 때 관련성이 있다고요 그리고 updateEntities를 호출해서 등록합니다 시스템은 이 재생 목록들을 올바른 컨텍스트에서 제안으로 표시합니다 한 번도 재생된 적 없더라도요 엔티티는 제거할 때까지 등록 상태를 유지합니다 특정 컨텍스트에서 removeAllEntities를 사용하거나 컨텍스트에서 특정 엔티티를 제거하거나 모든 컨텍스트의 엔티티를 전체 삭제할 수 있습니다

    이제 사람들이 콘텐츠를 발견하도록 돕는 옵션이 더 많아졌습니다 어떤 방법을 선택해야 할까요? Siri가 검색하고 가져올 수 있어야 할 때는 Spotlight를 사용하세요 앱 사용 방식을 Siri와 시스템에 가르치려면 인터랙션 기부를 사용하세요 패턴을 파악하고 사람들이 반복하고 싶어 할 액션을 제안할 수 있도록요 그리고 특정 상황에서 어떤 콘텐츠가 관련성이 있는지 시스템에 알리려면 RelevantEntities를 사용하세요 시스템이 올바른 순간에 제안할 수 있도록요 이 주제에 대해 더 알아보려면 Spotlight에 관한 새 문서를 확인하세요 그리고 인터랙션 기부도요 엔티티는 공유되고 시스템은 언제 관련성이 있는지 알게 됩니다 이제 더 효율적으로 만들어 봅시다

    여행 추적 앱으로 돌아가겠습니다 앱에는 랜드마크 사진이 있는데 사람들이 자신의 여행 사진도 저장할 수 있게 하고 싶었습니다 그래서 사진 앨범 보기를 추가하고 사진을 시스템에서 사용할 수 있도록 사진용 앱 스키마로 PhotoEntity를 정의했습니다 이렇게 하면 시스템이 Siri를 통해 내 사진을 처리하는 데 필요한 컨텍스트를 갖게 됩니다 Shortcuts와 Spotlight에서도요

    키워드로 사진에 태그를 달 수 있는 인텐트도 만들었습니다 사람들이 쉽게 정리하고 찾을 수 있도록요 사진 라이브러리가 커지면서 뭔가를 알아챘습니다 한 번에 많은 사진에 태그를 다는 게 예상보다 느렸습니다 코드를 살펴보면서 이유를 파악해 봅시다

    인텐트는 아주 단순합니다 사진에 키워드를 추가하기만 합니다 사진 엔티티 목록과 태그를 @Parameter로 받습니다 그리고 perform 메서드는 각 사진 항목에 태그를 적용합니다 그런데 실제로 왜 문제가 됐을까요?

    앱 인텐트가 파라미터를 리졸브하는 방식과 관련이 있습니다 인텐트가 실행되기 전에 시스템이 모든 엔티티를 리졸브합니다 엔티티 쿼리를 호출해서 모든 프로퍼티를 채우는 거죠 인텐트가 필요로 할 수 있는 모든 것을요 대부분의 인텐트에서는 그게 바로 원하는 동작입니다 하지만 제 경우에는 수백, 수천 개의 사진 엔티티를 리졸브하는 것을 의미했습니다 코드에 데이터 모델을 업데이트하기 위해 엔티티 ID만 필요한데도요 어떻게 고칠 수 있을까요? EntityCollection이 해결책입니다 완전히 리졸브된 엔티티 대신 엔티티 식별자 배열을 저장하는 새로운 타입입니다 파라미터 타입으로 EntityCollection을 사용하면 시스템이 인텐트의 perform 메서드에 식별자만 전달합니다 전체 엔티티를 리졸브하지 않고요 업데이트된 코드입니다 @Parameter 타입을 EntityCollection으로 변경하고 식별자를 태그 메서드에 직접 전달했습니다 필요한 것은 그것뿐이었습니다

    수정이 잘 됐는지 확인하기 위해 사진 1000장을 찾아서 태그를 달 단축어를 만들었습니다 먼저 사진 엔티티의 일반 배열로 실행했습니다

    그런 다음 EntityCollection으로 했더니 거의 즉시 완료됐습니다 코드 변경은 작지만 성능 차이는 상당합니다

    이제 같은 엔티티가 여러 기기에서 작동해야 한다면 어떨까요?

    2027 릴리스에서 Siri는 기기 간에 대화를 이어갈 수 있고 엔티티도 그 대화의 일부가 될 수 있습니다

    앱이 여러 기기에서 실행된다면 사람들이 한 기기의 Siri에서 대화를 시작하고 다른 기기에서 이어갈 수 있습니다 하지만 문제가 있습니다 iPhone의 Siri에게 사진을 앨범에 추가해 달라고 했다가 다른 기기로 전환해서 그 사진에 태그를 달아 달라고 하면 Siri가 그 사진을 찾지 못할 수 있습니다 이유를 이해하려면 엔티티가 어떻게 식별되는지 살펴봅시다 모든 엔티티에는 ID가 필요합니다 시스템이 찾는 방법이 그것이니까요 엔티티 ID는 각 기기에서 로컬로 생성될 수 있습니다 로컬 ID는 생성된 기기에서는 잘 작동합니다 하지만 각 기기마다 자체 로컬 ID를 생성합니다 그래서 같은 엔티티가 기기마다 다른 ID를 가질 수 있습니다 Siri가 기기 간에 엔티티를 참조하려면 어디서나 동일한 안정적인 ID가 필요합니다 서버에서 오거나 CloudKit 레코드 ID에서 올 수 있습니다 그러면 엔티티 ID가 안정적이라는 것을 시스템에 알려야 합니다 그게 SyncableEntity가 하는 일입니다 시스템에 엔티티 ID가 안정적이고 기기 간에 사용할 수 있다고 선언합니다 적용 방법을 살펴봅시다 엔티티에 SyncableEntity 프로토콜을 추가하는 것부터 시작합니다 그런 다음 안정적인 ID를 제공해야 합니다 엔티티가 이미 모든 기기에서 동일한 ID를 사용하고 있다면 서버에서 할당한 UUID나 CloudKit 레코드 ID처럼요 더 이상 변경이 필요 없습니다 하지만 CoreData 행 ID 같은 로컬 식별자를 사용한다면 두 가지가 필요합니다 로컬 ID와 안정적인 ID 모두요 SyncableEntityIdentifier는 이를 단일 ID로 묶어줍니다 기기에서는 코드가 로컬 ID를 사용하고 기기 간에는 시스템이 안정적인 ID를 사용합니다

    지금까지 엔티티에 집중했습니다 이제 엔티티를 사용하는 인텐트에 대해 이야기해 봅시다 인텐트는 파라미터를 받습니다 사람들이 제공하는 입력이죠 날짜, 이름, 주소 같은 것들이요 @Parameter를 선언하면 시스템이 기본 피커를 제공하고 Siri 이해와 현지화를 무료로 제공합니다 더 많은 기본 타입으로 같은 지원을 확장하고 있습니다 Duration에 대한 기본 지원을 추가합니다 커스텀 시간 피커를 만들 필요가 없어집니다 그리고 구조화된 이름 입력을 위한 PersonNameComponents도요 일반 문자열 대신요 그 외에도 더 있습니다

    각각 기본 피커가 있고 인텐트가 작동하는 모든 곳에서 사용됩니다 Siri, Shortcuts, Widget에서요 이것들은 개별 타입들입니다 @Parameter당 하나의 타입이죠 하지만 때로는 파라미터가 둘 이상의 타입을 받아야 합니다 유니온 값은 각 케이스가 다른 타입을 래핑하는 Swift 열거형입니다 단일 파라미터가 여러 옵션 중 하나를 나타낼 수 있게 합니다 이제 앱에 랜드마크와 여행 사진이 모두 있어서 사진 앨범이나 랜드마크 컬렉션의 사진을 보여주는 위젯을 만들고 싶었습니다 또는 랜드마크 컬렉션에서요 @UnionValue로 입력 파라미터를 지원하면 하나의 위젯으로 둘 다 사용할 수 있습니다 코드를 살펴보겠습니다 유니온 값을 열거형으로 정의합니다 @UnionValue 매크로와 함께요 각 케이스는 다른 엔티티 타입을 래핑합니다 랜드마크 컬렉션용 하나와 사진 앨범용 하나요 매크로가 시스템에 필요한 모든 것을 생성합니다 타입 정보, 케이스 메타데이터, 피커 지원까지요

    각 옵션이 피커에 어떻게 표시될지도 설정합니다 typeDisplayRepresentation은 전체 타입의 레이블이고 caseDisplayRepresentations는 각 케이스를 피커에 표시될 이름으로 매핑합니다 Widget에만 국한되지 않습니다 @UnionValue 파라미터는 인텐트가 작동하는 모든 곳에서 사용됩니다 Shortcuts 앱도 포함해서요

    자세한 내용은 여행 추적 샘플 코드 프로젝트를 확인해 보세요 그리고 해당 글도요 지금까지 다룬 모든 내용은 엔티티와 파라미터를 더 표현력 있고 효율적으로 만듭니다 이제 실행에 대해 이야기해 봅시다 Siri, Shortcuts, 또는 모든 시스템 표면에서 인텐트가 실행될 때 완료까지 30초만 있습니다 대부분의 일상적인 작업에는 충분합니다 하지만 모든 인텐트가 그렇게 빠르지는 않습니다 이제 앱이 사진 태그 및 정리를 지원하므로 사람들이 여행 사진을 공유할 수 있게 하고 싶었습니다 앱을 열지 않고 공유 앨범에 업로드하는 방식으로요 그래서 업로드 인텐트를 만들고 위젯에 버튼을 추가해서 트리거하게 했습니다 하지만 큰 사진의 경우 업로드에 시간이 걸리는데 인텐트가 계속 실패했습니다 완료하지 못했기 때문이죠 30초 제한 내에 LongRunningIntent가 이를 해결합니다 인텐트가 30초 제한을 넘어 실행되게 하고 앱의 백그라운드 작업 라이프사이클을 관리합니다 인텐트가 실행되는 동안 진행 상황 업데이트가 Live Activity로 자동 표시됩니다 코드를 살펴보겠습니다

    사진 업로드를 위해 작성한 인텐트입니다 LongRunningIntent를 준수하고 있습니다 사진 파일을 입력으로 받습니다 그리고 작업을 performBackgroundTask에 감쌉니다 확장된 실행을 위해서요

    LongRunningIntent는 인텐트가 진행 상황을 보고해야 합니다 시스템이 여전히 작동 중이고 중단되지 않았다는 것을 알도록요 ProgressReportingIntent를 기반으로 하므로 작업을 추적하는 내장 진행 객체를 얻습니다 파일의 청크 수를 계산하고 총 카운트를 설정합니다 그런 다음 각 청크를 업로드하면서 진행 상황을 업데이트합니다

    인텐트가 실행될 때 어떻게 되는지 보겠습니다 더 오래 실행될 수 있고 Live Activity에 정지 버튼이 있어서 사용자가 언제든지 취소할 수 있습니다 인텐트가 중단되기 전에 미리 알 수 있다면 좋겠습니다

    CancellableIntent는 취소 시 원활하게 정리할 수 있게 합니다 사용자가 취소를 탭하거나 시스템이 타임아웃되거나 리소스를 회수해야 할 때요 취소 지원을 추가하는 방법입니다

    CancellableIntent를 추가하고 onCancel 핸들러를 구현합니다 취소 이유가 발생하면 핸들러가 이유를 알려줍니다 그것을 사용해서 부분 업로드를 정리하거나 진행 중인 요청을 취소할 수 있습니다 LongRunningIntent는 지원 기기에서 백그라운드 GPU 접근도 지원합니다 사진 처리나 온디바이스 추론 같은 작업에 사용됩니다 앱의 권한에 GPU 접근을 반드시 추가하세요 백그라운드에서 작업을 실행하는 메커니즘에 대해 더 알아보려면 WWDC25의 이 영상을 확인해 보세요 지금까지 인텐트가 얼마나 오래 실행되는지 그리고 중단될 때 어떻게 되는지 다뤘습니다 이제 어떤 프로세스가 실행하는지 이야기해 봅시다 앱이 성장하면서 일부 인텐트를 Widget extension으로 이동하거나 App Intents extension으로 이동할 수 있습니다 가벼운 별도 프로세스로 앱을 실행하지 않고도 요청을 처리할 수 있습니다

    또한 공유 Swift 패키지를 만들 수도 있습니다 인텐트와 엔티티가 있는 프레임워크나 앱과 extension에 가져올 수 있는요 사실 여행 추적 앱에서 그렇게 했습니다 모든 인텐트가 공유 패키지에 있고 메인 앱과 위젯 extension 모두에서 가져옵니다 인텐트, 엔티티, 쿼리가 이런 공유 패키지에 있고 앱과 extension이 링크할 때 시스템은 결정해야 합니다 요청이 들어오면 각 인텐트를 어떤 프로세스에서 실행할지요 시스템은 휴리스틱을 기반으로 대상을 선택합니다 앱이 이미 실행 중이면 앱을 우선시하고 그렇지 않으면 extension을 실행합니다 하지만 그것이 항상 올바른 선택은 아닙니다 예를 들어 위젯에 즐겨찾기 버튼을 추가하고 싶었습니다 홈 화면에서 바로 사진을 즐겨찾기로 표시할 수 있도록요 위젯은 앱과 데이터 모델을 공유하지만 두 프로세스가 같은 데이터 저장소에 쓰면 충돌이 생길 수 있습니다 그래서 위젯에 읽기 전용 접근을 주고 메인 앱이 모든 쓰기를 처리하게 했습니다 누군가 그 버튼을 탭하면 인텐트가 메인 앱에서 실행되어야 합니다 ExecutionTargets를 사용하면 시스템에 알릴 수 있습니다 정확히 어떤 프로세스가 인텐트를 실행해야 하는지요 방법은 이렇습니다

    메인 앱을 대상으로 지정하거나

    appIntentsExtension을 지정하거나 widgetKitExtension을 지정하거나 어떤 조합도 가능합니다 ExecutionTargets를 사용하면 시스템의 휴리스틱을 재정의하고 어떤 프로세스가 인텐트를 처리하는지 정확히 제어할 수 있습니다 공유하고 싶었던 새 기능을 이렇게 마무리하겠습니다 다음 단계로 엔티티에 ValueRepresentation을 추가해서 앱 간에 구조화된 데이터를 전달할 수 있게 하세요 시스템에 관련 콘텐츠를 등록하세요 올바른 순간에 표시될 수 있도록요 EntityCollection을 도입해서 인텐트를 더 빠르게 만드세요 많은 수의 엔티티를 처리할 때요 그리고 30초 이상 걸리는 인텐트에는 LongRunningIntent를 추가하세요 앱의 Siri 경험을 단계별로 구축하려면 "Code-along: Make your app available to Siri"를 확인하세요 그리고 새로운 AppIntentsTesting 프레임워크로 인텐트를 테스트하려면 "Validate your App Intents adoption with AppIntentsTesting"을 확인하세요 여러분이 만들 것이 기대됩니다 시청해 주셔서 감사합니다!

    • 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."

Developer Footer

  • 비디오
  • WWDC26
  • App Intents 프레임워크의 새로운 기능 살펴보기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • Apple Intelligence
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝 및 AI
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • Mini Apps Partner Program
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    최신 뉴스 읽기.
    Apple Developer 앱 받기.
    Copyright © 2026 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침