안녕하세요! 피피아노입니다 🎵
이번 포스팅에서는 App Intents 프레임워크에 대해서 정리를 해보려고 합니다.
관심 있으신 분들은 아래 영상을 참고하시면 좋을 것 같습니다.
https://developer.apple.com/kr/videos/play/wwdc2025/244
앱 인텐트 알아보기 - WWDC25 - 비디오 - Apple Developer
앱 인텐트 프레임워크에 대해 알아보고 Apple의 개발자 플랫폼 내에서 점점 더 중요해지는 이 프레임워크의 역할에 대해 살펴보세요. 인텐트, 엔티티, 쿼리 등 핵심 개념을 차근차근 설명합니다.
developer.apple.com
그럼 바로 시작하겠습니다!
App Intents란 무엇인가?
App Intents는 시스템 전체 및 모든 Apple 플랫폼에서 앱의 발견 가능성, 가시성, 기능을 확장해 주는 프레임워크입니다. 단순히 기능을 빌드하기 위해 앱으로 가져오는 프레임워크가 아니라, 앱의 기능을 시스템 전체로 확장해 주는 생태계라고 할 수 있습니다.
제공하는 경험
- Spotlight 검색에서 맞춤형 결과
- Siri를 통한 음성 명령 실행
- 동작 버튼 및 Apple Pencil Pro 연동
- 위젯과 제어 센터에서 바로 실행
올해부터는 Mac의 Spotlight에서도 앱 동작을 직접 실행할 수 있습니다.
핵심 구조
1. Intent - 앱의 "동사"
앱이 실행할 수 있는 동작을 정의합니다. "메모 열기", "운동 시작", "쇼핑 목록 추가" 같은 액션들이죠.
2. AppEnum vs AppEntity - 앱의 "명사"
- AppEnum: 고정된 값들 (예: 앱 섹션 - 지도, 랜드마크, 컬렉션)
- AppEntity: 동적인 데이터 (예: 개별 랜드마크들)
3. App Shortcut - 시스템 노출
Intent를 시스템 전체에 자동으로 노출시키는 방법입니다.
실제 예시: 여행 앱
랜드마크를 탐색하는 여행 앱을 예로 들어보겠습니다.
기본 Intent 만들기
struct NavigateToLandmarksIntent: AppIntent {
static var title: LocalizedStringResource = "랜드마크 보기"
static var supportedModes: [AppIntentMode] = [.foreground]
@MainActor
func perform() async throws -> some IntentResult {
SharedNavigator.shared.navigate(to: .landmarks)
return .result()
}
}
매개변수 추가하기
앱 섹션을 선택할 수 있도록 AppEnum을 만들고,
enum NavigationOption: String, AppEnum {
case landmarks, map, collections
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "탐색 옵션")
// DisplayRepresentation으로 각 옵션에 아이콘 추가 가능
}
Intent에 매개변수로 추가해줍니다.
@Parameter(title: "섹션")
var section: NavigationOption
App Shortcut으로 노출
struct AppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: NavigateIntent(),
phrases: ["\(.applicationName)에서 \(.section) 열기"],
shortTitle: "탐색"
)
}
}
동적 데이터: AppEntity 활용
랜드마크 같은 동적 데이터는 AppEntity로 처리합니다.
Entity 정의
struct LandmarkEntity: AppEntity {
var id: UUID
@Property(title: "이름")
var name: String
@Property(title: "위치")
var state: String
static var defaultQuery = LandmarkQuery()
}
Query 구현
시스템이 엔티티를 이해할 수 있도록 Query를 제공해줍니다.
struct LandmarkQuery: EntityQuery {
func entities(for identifiers: [UUID]) async throws -> [LandmarkEntity] {
// ID로 엔티티 조회 로직
}
func suggestedEntities() async throws -> [LandmarkEntity] {
// 추천 랜드마크 반환
}
}
고급 기능들
Transferable로 데이터 공유
엔티티의 이미지나 다른 데이터를 앱 간에 공유하거나 단축어에서 활용할 수 있도록 설정하기
extension LandmarkEntity: Transferable {
static var transferRepresentation: some TransferRepresentation {
DataRepresentation(contentType: .jpeg) { landmark in
try await landmark.imageData()
}
}
}
이렇게 해주면 단축어에서 "Show Content" 액션으로 랜드마크 이미지를 직접 표시하거나, 다른 앱으로 이미지를 전달할 수 있습니다.
Spotlight 통합
extension LandmarkEntity: IndexedEntity {
@Property(title: "이름")
@SpotlightIndexingKey(\.title)
var name: String
}
@SpotlightIndexingKey를 사용하면 해당 속성이 Spotlight에서 검색 가능해지고, 사용자가 관련 키워드로 검색했을 때 결과에 나타나게 해줄 수 있습니다.
딥링킹
Spotlight에서 엔티티를 탭했을 때 앱 내 특정 화면으로 바로 이동하도록 설정
struct OpenLandmarkIntent: OpenIntent {
@Parameter(title: "랜드마크")
var target: LandmarkEntity
// OpenIntent는 자동으로 앱을 열고 실행
}
OpenIntent 프로토콜을 채택하면 자동으로 앱을 포그라운드로 가져온 후 실행되므로, supportedModes 설정이 불필요합니다.
아키텍처 고려사항
빌드 타임 처리
- App Intents는 컴파일 시점에 메타데이터 생성
- Intent의 title 등은 반드시 상수여야 함
- 시스템이 앱 실행 없이도 기능을 이해할 수 있음
다중 타겟 지원
여러 타겟에서 App Intent 타입을 공유하려면 AppIntentsPackage 등록이 필요합니다.
struct SharedIntentsPackage: AppIntentsPackage {}
struct MyAppPackage: AppIntentsPackage {
static var includedPackages: [any AppIntentsPackage.Type] = [
SharedIntentsPackage.self
]
}
감사합니다.
잘못된 내용이 있거나 더 좋은 내용 피드백은 언제나 환영합니다!
궁금하신 부분은 댓글로 질문 부탁드립니다!
'Apple > Swift' 카테고리의 다른 글
[Swift] Multipeer Connectivity 톺아보기 (5) | 2025.08.23 |
---|---|
[Swift] Swift Testing 톺아보기 (6) | 2025.07.02 |
[Swift] suffix()로 인한 시간 초과 문제 해결하기 (8) | 2025.06.27 |
[Swift] Foundation Models Framework (6) | 2025.06.22 |
[Swift] Core ML과 MFCC를 활용한 감정 추론 (7) | 2025.05.14 |