Widget 기본 설정해보기

2025. 4. 5. 01:16Apple/SwiftUI

Xcode 에서 Project 생성 시 - Multiplatform > App 선택하기, iOS 의 App 선택이 아니다.

 

Process

1. WeatherData.swift 파일에서 날씨 관련 Dummy Data(더미데이터 - 임시 데이터)와 TimelineEntry 타입 안에 설정될 

날짜, 도시, 기온, 날씨 설명, 아이콘, 이미지들을 설정해준다.

 

2. ContentView.swift 파일에서 WeatherType 이라는 Hashable 타입의 구조체를 생성해준다. 

→ NavigationLink 나 List 같은 SwiftUI 뷰를 사용시, 고유 비교가 필요한 경우를 위해 Hashable 채택

→ Hashable 을 채택해야 NavigationStack dptj .navigationDestination(for:) 에 사용할 수 있다. 

→ Swift 구조체의 기본 멤버와 값 비교 가능

  • ContentView 안에 NavigationStack 을 사용해 WeatherType 기반으로 이동 할 수 있다. 

3. WeatherWidget 파일을 WidgetDemo 프로젝트에 New > file 로 생성하는 것이 아니라, Xcode 내비게이션 창 옆 File > Target > Application Extension > WidgetExtension 을 선택하고, Active 까지 눌러줘야한다. 

 

 

4. WeatherWidget 폴더가 생성되고 그 안에 WeatherWidget 이라는 파일이 기본적으로 주어지는데, 이곳에서도 기본적인 더미데이터가 있음으로 WeatherData 나 WeatherType 을 설정해둔 것과 알맞게 수정도 해줘야 했다. 또한, 구 버전의 교재 코드라 유의할 점이 조금 많았다. 

struct WeatherEntry: TimelineEntry {
    var date: Date
    let city: String
    let temperature: Int
    let description: String
    let icon: String
    let image: String
}

 

TimelineEntry 프로토콜을 채택해야 WidgetKit 을 받아들일 수 있다. 이 프로토콜은 필수로 date 속성이 있어야 한다. 이 시점을 기준으로 위젯이 표시될 때가 결정된다고 한다.

 

5. WeatherWidgetEntryView 라고 구조체 뷰를 설정해줬는데 이 뷰는 위젯에 보여질 실제 뷰이며. Provider.Entry 는 WeatherEntry 로 타입이 추론된다. 

6. WeatherSubView 위젯 내부의 뷰를 모듈화한 서브 뷰, 똑같은 데이터를 다른 레이아웃에서 재사용할 수 있게 된다. 

 

  • 뷰 컴포넌트 분리 (재사용성 높임)
  • ContainerRelativeShape() 는 iOS 16+ 에서 적용 가능한 스타일 요소

 

7. WeatherWidget

struct WeatherWidget: Widget {
    let kind: String = "WeatherWidget"
    ...
}

 

 

  • 위젯 메타 정보 (종류, 이름, 인텐트, 뷰 렌더링 방식 등) 정의
  • 앱이 위젯을 등록할 때 이 구조체가 사용됨

구버전(교재)와 현재 Xcode 16.x 에서 달라진 점 비교

기능구버전 (교재)최신 Xcode 16.x

기능 구버전(교재) 현재 Xcode 16.x
Provider 프로토콜 IntentTimelineProvider AppIntentTimelineProvider ✅
Configuration IntentConfiguration AppIntentConfiguration ✅
containerBackground 없음 필수
WidgetKind 실행 변수 없음 환경 변수 지정 필수
Preview 오류 거의 없음 설정 까다로움 (배경 누락 시 에러)

 

📌 유의 - 오류가 발생할 수 있는 부분 

// ❌ 구버전
IntentConfiguration(kind: "MyWidget", intent: MyIntent.self, provider: Provider()) { entry in
    MyEntryView(entry: entry)
}

// ✅ 최신버전
AppIntentConfiguration(kind: "MyWidget", intent: MyAppIntent.self, provider: Provider()) { entry in
    MyEntryView(entry: entry)
        .containerBackground(.fill.tertiary, for: .widget) // 🔥 필수
}

.containerBackground(.fill.tertiary, for: .widget) 이 부분을 꼭 추가해야. Preview 를 보려고 할 때 오류가 안난다.

 

 

결과 화면

마지막 실기기로 Widget 추가를 WidgetDemo 프로젝트 네임의 Widget 으로 하면 더미데이터인 London 날씨와 화씨 온도가 함께 뜬다. 이번 교재 내용은 위젯 설정만 하는 것이다. 다음 장에서는 위젯의 크기 설정과 딥링크 부분을 살펴봐야겠다.

 

* 핵심만 골라배우는 SwiftUI 기반의 iOS 프로그래밍 - 닐 스미스 (개정보증판) 을 기반으로 실습한 내용입니다.

기존의 개념 설명이나 에러 처리는 gpt 와 함께 했습니다. 

 

 

실습코드: Github - WidgetDemo