iOS 26 위젯 표면: 하나의 App Intent, 여러 곳에서
오랫동안 위젯은 하나의 스냅샷이었습니다. 시스템이 타임라인 위에 뷰를 렌더링하면 사용자는 그것을 바라보았고, 어디를 탭하든 앱이 열렸습니다. 그 모델은 이제 사라졌습니다. iOS 17부터 위젯은 아무것도 실행하지 않고도 코드를 돌리는 버튼과 토글을 담을 수 있게 되었고, 그 버튼이 실행하는 코드가 바로 App Intent입니다1. 제어 센터 컨트롤도, Live Activity 안의 버튼도 마찬가지입니다. 이 점이 눈에 들어오는 순간, iOS 26의 위젯 표면은 세 개의 서로 다른 API처럼 보이기를 멈추고 하나로 보이기 시작합니다. 즉, 시스템이 여러분의 App Intents를 렌더링해 주는 여러 장소들이며, 저마다 화면 공간만 다를 뿐 그 아래의 배관은 동일합니다.
이 재구성이 이 글 전체의 핵심입니다. App Intent를 한 번 익혀 두면 홈 화면, 잠금 화면, 제어 센터, 동작 버튼, Dynamic Island, 그리고 (또다시 같은 intent로) Siri와 Apple Intelligence까지 모두 살아납니다. 반대로 서로 단절된 세 가지 기능을 따로 작성하면, 더 나쁜 결과를 위해 네 배의 일을 하게 됩니다.
핵심 요약
- 인터랙티브 위젯 (iOS 17 이상): 위젯 뷰 안에
Button(intent:)이나Toggle(isOn:intent:)를 넣으면, 시스템이 앱을 띄우지 않고 위젯 익스텐션 안에서 App Intent의perform()을 실행한 뒤 타임라인을 다시 불러옵니다1. - 제어 센터 컨트롤 (iOS 18 이상):
ControlWidgetButton이나ControlWidgetToggle로 만든ControlWidget은 같은 App Intents를 기반으로 하며, 제어 센터, 잠금 화면, 동작 버튼에 나타납니다2. - Live Activity (ActivityKit):
ActivityAttributes와ActivityConfiguration이 잠금 화면과 Dynamic Island를 구동하고, 서버가 주도하는 업데이트는 푸시로 전달되며, 그 안의 버튼들 역시 App Intent입니다3. - iOS 26가 더한 것은 렌더링이지 모델이 아닙니다: 위젯은 Liquid Glass 표현 방식과 강조 렌더링 모드를 받아들였지만, App Intents를 노출 지점으로 삼는 아키텍처는 iOS 18 때와 달라지지 않았습니다4.
- 이 모든 것을 하나로 묶는 사실은 이렇습니다. 위젯 버튼, 컨트롤, Siri 발화, Apple Intelligence 동작이 전부 같은 App Intent일 수 있다는 것입니다. 기능은 한 번만 설계하십시오.
인터랙티브 위젯: 앱을 열지 않는 버튼
작동 원리는 단순하니 정확히 짚고 넘어갈 가치가 있습니다. 위젯 뷰에 SwiftUI Button이나 Toggle을 추가하되, 동작 클로저 대신 App Intent를 넘깁니다1.
struct WaterWidgetView: View {
let logged: Int
var body: some View {
VStack {
Text("\(logged) glasses")
Button(intent: LogWaterIntent()) {
Label("Add", systemImage: "plus")
}
}
}
}
사용자가 탭하면 시스템은 위젯 익스텐션 안에서 LogWaterIntent.perform()을 실행합니다. 앱은 실행되지 않습니다. intent가 제 할 일(공유 저장소에 기록, 카운트 갱신)을 마치면, 위젯 타임라인이 다시 불러와져 그 결과를 보여 줍니다.
Toggle은 SetValueIntent를 통해 같은 방식으로 작동하는데, 이 intent는 사용자가 방금 설정한 새 켜짐/꺼짐 값을 받습니다.
struct ToggleReminderIntent: SetValueIntent {
static let title: LocalizedStringResource = "Toggle Reminder"
@Parameter(title: "Enabled")
var value: Bool
func perform() async throws -> some IntentResult {
ReminderStore.shared.enabled = value
return .result()
}
}
위젯은 Toggle(isOn: store.enabled, intent: ToggleReminderIntent())를 바인딩하고, 시스템은 value를 새 상태로 설정한 뒤 perform()을 실행하고 화면을 다시 그립니다. 버튼과 같은 형태에 매개변수 하나가 더해졌을 뿐입니다1.
여기서 할 수 있는 일은 두 가지 제약이 규정하며, 둘 다 어기기 쉽습니다. 첫째, perform()은 실행 예산이 빠듯한 제한된 위젯 익스텐션 환경에서 돌아갑니다. 즉, 빠른 상태 변경을 위한 것이지 네트워크 업로드나 무거운 연산을 위한 것이 아닙니다. 둘째, 위젯은 상태를 반영할 뿐 임의의 UI를 애니메이션으로 보여 주지 않습니다. 데이터를 바꾸면 타임라인이 다시 렌더링되는 것이지, 직접 만든 전환 효과를 돌리는 것이 아닙니다. 상호작용을 “값을 뒤집고, 새 값을 보여 준다”로 설계하면 잘 작동합니다. 그 이상을 욕심내면 시스템이 여러분과 싸웁니다.
제어 센터 컨트롤: 같은 intent, 다른 방
iOS 18은 제어 센터, 잠금 화면, 동작 버튼을 서드파티 컨트롤에 개방했고, 그 API는 위젯과 의도적으로 나란한 구조입니다2. 컨트롤은 ControlWidget이며, 그 본문은 App Intent에 연결된 ControlWidgetButton이나 ControlWidgetToggle입니다.
struct LogWaterControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "com.example.logWater") {
ControlWidgetButton(action: LogWaterIntent()) {
Label("Log Water", systemImage: "drop.fill")
}
}
}
}
LogWaterIntent가 이미 인터랙티브 위젯을 구동하고 있다면, 컨트롤은 거의 공짜로 얻어집니다. 같은 intent에 새 껍데기만 씌우면 되니까요. 이것이 바로 아키텍처가 보상을 돌려주는 순간입니다. 컨트롤은 그 기능의 두 번째 구현이 아니라, 이미 작성해 둔 기능을 거는 두 번째 장착 지점일 뿐입니다. 토글 컨트롤은 위젯 토글과 똑같이 SetValueIntent를 사용하므로, “음소거”, “세션 시작”, “다크 모드 전환” 같은 기능을 한 번만 만들어 두면 새로운 로직 없이도 제어 센터, 잠금 화면, 동작 버튼에 그대로 나타납니다2.
Live Activity: 스스로 갱신되는 표면
Live Activity는 세 번째 장소이자, 움직이는 부품이 가장 많은 곳입니다. ActivityAttributes 타입이 정적 콘텐츠와 동적 콘텐츠를 정의하고, ActivityConfiguration이 잠금 화면 표현과 Dynamic Island 영역을 렌더링하며, ActivityKit이 액티비티를 시작·갱신·종료합니다3. Live Activity 안의 버튼 역시 App Intent이므로, Dynamic Island의 “일시 정지”나 “다음” 컨트롤은 위젯 버튼과 똑같은 종류의 intent를 실행합니다.
Live Activity를 별도의 분야로 만드는 부분은 갱신 경로입니다. 로컬에서 직접 갱신하는 타이머는 간단합니다. 그러나 서버에서 일어나는 이벤트(배달 위치 이동, 경기 점수 변화)로 구동되는 액티비티는 푸시로 갱신됩니다. pushTokenUpdates에 등록하고, 백엔드에서 ActivityKit 푸시 페이로드를 보내면, 앱이 전혀 실행되지 않는 상태에서도 시스템이 잠금 화면과 Dynamic Island를 갱신합니다3. 이것은 진정으로 강력한 동시에 진정으로 망치기 쉬운데, 이제 액티비티의 정확성이 단순한 로컬 코드가 아니라 서버 계약, 푸시 신뢰성, 그리고 만료 시점 정책에 달려 있기 때문입니다.
iOS 26가 실제로 바꾼 것
iOS 26 위젯의 헤드라인은 표현 방식이지 아키텍처가 아닙니다. 위젯은 Liquid Glass 머티리얼을 받아들이고 강조 렌더링 모드를 갖추어, 시스템의 새 디자인 언어와 어울리고 OS가 콘텐츠 색을 다시 입히는 맥락에서 올바르게 색조를 띱니다4. 이것은 홈 화면, 잠금 화면, StandBy 전반에서 위젯이 어떻게 보이는가에 영향을 주므로, 디자인을 한 번 손볼 만한 가치가 있습니다. 하지만 상호작용이 작동하는 방식은 바꾸지 않습니다. iOS 18에서 인터랙티브 위젯과 컨트롤을 만들었다면, iOS 26으로의 이동은 시각적 리프레시이지 재작성이 아닙니다. iOS 26가 인터랙티브 위젯을 “도입했다”는 주장은 의심하며 받아들이십시오. 상호작용성은 iOS 17에, 컨트롤은 iOS 18에 출시되었고, iOS 26는 그것들을 시스템의 나머지와 닮아 보이게 만들었을 뿐입니다.
다만 Liquid Glass가 디자인에 미치는 함의는 실제적입니다. 위젯은 시스템이 배경화면 위에 합성하고 유리 크롬을 통해 굴절시키는 콘텐츠이므로, 앱에서의 Liquid Glass를 다스리는 것과 같은 규칙이 적용됩니다. 기능 레이어와 콘텐츠 레이어의 구분을 존중하고, 유리가 읽어 낼 수 없는 무거운 커스텀 배경으로 머티리얼과 싸우지 마십시오.
아키텍처를 단순하게 말하면
기억해 둘 만한 모델은 이렇습니다. App Intent는 이름이 붙고, 타입이 정해지고, 설명이 달린 하나의 기능입니다. iOS는 그 기능을 장착할 장소를 점점 늘려 줍니다.
- 위젯 안의
Button또는Toggle. - 제어 센터, 잠금 화면, 동작 버튼의
ControlWidget. - Live Activity와 그 Dynamic Island 안의 버튼.
- Siri 발화와 단축어 동작.
- Apple Intelligence가 사용자를 대신해 호출할 수 있는 동작5.
이 모든 것이 perform() 메서드를 가진 같은 AppIntent 타입입니다. 핵심은 그 기능을 잘 설계하는 데 있습니다. 명확한 이름, 타입이 정해진 매개변수, 빠르고 멱등한 perform(), 그리고 합리적인 결과 말입니다. 이것을 한 번만 잘해 두면 노출 지점들은 껍데기가 됩니다. 이는 제가 App Intents를 앱으로 들어가는 진짜 API라고 말했던 논지, 그리고 오늘날 iOS 앱이 드러내는 세 가지 표면에 관해 했던 논지와 같습니다. 위젯 표면은 여러분이 만들어 내는 기능이 아니라, 기능이 일단 존재하기만 하면 그것들이 모습을 드러내는 장소입니다.
굳이 만들 필요가 없을 때
위젯 표면은 한눈에 볼 만한 상태와 빠른 동작이 진짜로 있는 앱에 보상을 줍니다. 트래커, 타이머, 토글, 지금 재생 중 컨트롤 같은 것 말입니다. 모든 것에 보상을 주지는 않습니다.
- 한눈에 볼 상태가 없으면 위젯도 없습니다. 앱을 열지 않고 보여 줄 만한 것이 아무것도 없다면, 위젯은 유지보수 부담과 추가 익스텐션 타깃만 치르게 하는 장식일 뿐입니다.
- 무겁거나 느린 동작은 이곳의
perform()에 어울리지 않습니다. 위젯과 컨트롤의 실행 환경은 제한적입니다. 동작이 실제 시간이나 실제 연산을 필요로 한다면, 버튼은 익스텐션 안에서 일을 하는 척할 게 아니라 준비된 상태로 앱을 열어야 합니다. - 라이브하지 않은 것에 Live Activity를 쓰는 일. Live Activity는 시간이 한정되고 능동적으로 변하는 이벤트를 위한 것입니다. 이것을 지속적인 상태 배지로 쓰는 것은 표면을 잘못 읽은 것이며, 액티비티 예산에 관해 시스템의 블랙리스트에 오르는 지름길입니다.
기술은 세 개의 API를 배우는 데 있지 않습니다. 장착할 가치가 있는 App Intents를 설계하고, 그것들을 사용자가 이미 있는 곳에 장착하는 데 있습니다. 사용자가 들여다보는 홈 화면, 쓸어 올려 여는 제어 센터, 이미 무언가를 보여 주고 있는 Dynamic Island 말입니다. 기능을 한 번, 안목을 갖고 만들어 두면 iOS가 그 표면들을 공짜로 건네줍니다.
자주 묻는 질문
iOS 26가 인터랙티브 위젯을 도입했나요?
아닙니다. 인터랙티브 위젯은 iOS 17에, 제어 센터 컨트롤은 iOS 18에 출시되었습니다. iOS 26는 그것들이 Liquid Glass 머티리얼과 강조 렌더링을 받아들여 시스템 디자인 언어와 어울리게 만들었을 뿐입니다4. iOS 26가 인터랙티브 위젯을 “도입했다”는 주장은 의심하며 받아들이십시오. iOS 26의 변화는 시각적 리프레시이지 재작성이 아닙니다.
iOS 위젯 안의 버튼은 실제로 어떻게 일을 하나요?
버튼은 App Intent를 실행합니다. 위젯의 Button이나 Toggle은 perform() 메서드를 가진, 이름과 타입이 정해진 AppIntent를 호출하므로, 위젯은 앱을 열지 않고 동작합니다. 같은 intent가 제어 센터 컨트롤, Live Activity 버튼, Siri 발화, 단축어 동작을 함께 구동합니다5.
iOS 26에서 위젯에 실제로 바뀐 것은 무엇인가요?
아키텍처가 아니라 표현 방식입니다. 위젯은 Liquid Glass를 받아들이고 강조 렌더링 모드를 갖추어 홈 화면, 잠금 화면, StandBy 전반에서 올바르게 색조를 띱니다4. 상호작용성은 iOS 18 때와 똑같이 작동하므로, 기존 인터랙티브 위젯에는 재작성이 아니라 디자인을 한 번 손보는 작업이 필요합니다.
Live Activity는 앱이 실행되지 않을 때 어떻게 갱신되나요?
푸시로 갱신됩니다. pushTokenUpdates에 등록하고 백엔드에서 ActivityKit 푸시 페이로드를 보내면, 앱이 실행되지 않아도 시스템이 잠금 화면과 Dynamic Island를 갱신합니다3. 그래서 액티비티의 정확성은 단순한 로컬 코드가 아니라 서버 계약, 푸시 신뢰성, 만료 시점 정책에 달리게 됩니다.
하나의 App Intent는 어디에 나타날 수 있나요?
같은 AppIntent 타입이 위젯의 Button/Toggle, 제어 센터 / 잠금 화면 / 동작 버튼의 ControlWidget, Live Activity와 그 Dynamic Island, Siri 발화, 단축어 동작, 그리고 Apple Intelligence가 호출할 수 있는 동작에 장착됩니다5. 기능을 한 번만 설계하면 노출 지점들은 껍데기가 됩니다.
위젯이나 Live Activity를 만들지 말아야 할 때는 언제인가요?
앱을 열지 않고 보여 줄 만한, 한눈에 볼 상태가 없다면 위젯은 건너뛰십시오. 제한된 위젯 환경에서는 무겁거나 느린 동작을 perform() 바깥에 두고, 대신 준비된 상태로 앱을 여십시오. 그리고 Live Activity를 지속적인 상태 배지로 쓰지 마십시오. Live Activity는 시간이 한정되고 능동적으로 변하는 이벤트를 위한 것이며, 이를 오용하면 액티비티 예산을 태워 버립니다.
-
Apple Developer, “Adding interactivity to widgets and Live Activities”. 인터랙티브 위젯(iOS 17 이상)은
AppIntent(토글의 경우SetValueIntent)를 기반으로 한 SwiftUIButton(intent:)과Toggle(isOn:intent:)를 사용합니다. intent의perform()은 앱을 띄우지 않고 위젯 익스텐션 안에서 실행되며, 타임라인이 다시 불러와져 결과를 반영합니다. ↩↩↩↩ -
Apple Developer, “Creating controls to perform actions across the system” 및
ControlWidget프로토콜. 컨트롤(iOS 18 이상)은 App Intents에 연결된ControlWidgetButton과ControlWidgetToggle로 만들어지며, 제어 센터, 잠금 화면, 동작 버튼에 나타납니다. ↩↩↩ -
Apple Developer, “ActivityKit” 및 “Displaying live data with Live Activities”.
ActivityAttributes와ActivityConfiguration이 잠금 화면과 Dynamic Island를 정의하고 렌더링하며, ActivityKit이 액티비티를 시작·갱신·종료합니다. 서버가 주도하는 업데이트는pushTokenUpdates와 함께 푸시를 사용합니다. ↩↩↩↩ -
iOS 26 위젯 렌더링: 위젯은 Liquid Glass 머티리얼과 강조 렌더링 모드를 받아들이며, 이는
WidgetRenderingMode와\.widgetRenderingMode환경 값으로 제어됩니다. 상호작용 모델(위젯과 컨트롤의 App Intents)은 iOS 17(위젯)과 iOS 18(컨트롤) 때와 달라지지 않았습니다. Apple, “WWDC 2025: the new software design” 및 WidgetKit 문서. ↩↩↩↩ -
Apple Developer, “App Intents”. 같은
AppIntent타입이 Siri, 단축어, Spotlight, 위젯 및 컨트롤 표면, 그리고 Apple Intelligence를 통해 시스템이 드러내는 단위입니다. 교차 표면 모델에 대한 저자의 분석: App Intents는 여러분의 앱으로 들어가는 Apple의 새로운 API, App Intents 2와 iOS 26의 추가 기능, 그리고 iOS 앱의 세 가지 표면. ↩↩↩