본문 바로가기
Swfit

ActivityKit으로 Dynamic Island 만들어보기!

by GGShin 2023. 10. 21.

1. Widget Extension 추가하기

1) App project를 생성해 준 다음, File -> New -> Target 선택.

2) widget extension을 검색해서 타겟을 추가해준다. 

 

3) Info.plist에 Supports Live Activities를 추가하고 YES로 value를 설정해준다.

주의: SwiftUI 프로젝트에는 navigation panel에 info.plist가 안보이므로, Targets에 들어가서 수정해주면 된다.

2. ActivityAttributes 모델 생성

 

1. Swift 파일로 ActivityAttributes를 conform하는 struct를 하나 만들어 준다.

 

 

 

 

 

 

 

 

 

 

 

 

주의: ActivityAttributes는 Target Membership에 앱과 위젯 extension 모두 체크해 주어야 한다. (그래야 두 곳 모두에서 사용이 가능하다.)

간단하게 이미지와 텍스트 정도를 보여줄 수 있는 모델 생성.

ContentState는 정보가 업데이트되는 경우 바뀌는데, 정보가 업데이트 되면 Live Activity도 업데이트 된다. 

정보에 따라 어떤 식의 UI를 보여줄 것인지는 Live Activity 파일에서 설정해 준다.

 

3. LiveActivity 파일 수정

Wiget Target을 추가해줄 때, 몇 가지 보일러 플레이트 코드들이 작성되어 있다. 다 지워주고 원하는 화면을 그려주고 데이터를 바인딩 해주면 된다. 

import ActivityKit
import WidgetKit
import SwiftUI

struct SimpleStatusLiveActivity: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: SimpleAttributes.self) { context in
            // Lock Screen UI 부분
            HStack(content: {
                Image(systemName: context.state.currentImage)
                    .foregroundStyle(.teal)
                Text("Lv.\(context.state.currentLevel)")
                    .foregroundStyle(.yellow)
            })
            
            
        } dynamicIsland: { context in
            // Dynamic Island UI 부분
            DynamicIsland {
                // Expanded (DI 눌렀을 때 가장 커진 화면)
                DynamicIslandExpandedRegion(.leading) {
                    Text("Lv.\(context.state.currentLevel)")
                        .foregroundStyle(.teal)
                }
                
                // Compact: 앱의 DI가 보여주는 선순위 일때 나오는 화면
            } compactLeading: {
                Image(systemName: context.state.currentImage)
                    .foregroundStyle(.pink)
            } compactTrailing: {
                Text("Lv.\(context.state.currentLevel)")
                    .foregroundStyle(.teal)
                    
            } minimal: { // Minimal: 앱의 DI가 보여주는 2순위 일때 나오는 화면
                // Minimal
                Text("Lv.\(context.state.currentLevel)")
                    .foregroundStyle(.teal)
            }
            
        }

    }
}

Lock Screen, Dynamic Island 설정 별 화면을 그려주고 먼저 설정해 둔 attributes의 어떤 값들을 바인딩 해줄지 명시해주면 된다.

 

4. StatusBundle에 만들어 준 LiveActivity initialize 하기

import WidgetKit
import SwiftUI

@main
struct SimpleStatusBundle: WidgetBundle {
    var body: some Widget {
        SimpleStatusLiveActivity() // 시작할 LiveActivity struct init 해주기
    }
}

 

5. Activity request 하기

import SwiftUI
import WidgetKit
import ActivityKit

struct ContentView: View {

    var body: some View {
        requestActivity()
    }
    
    // Activity request 해주는 메서드.
    private func requestActivity() -> some View {
        do {
          
          	// 1. Attribute init.
            let att = SimpleAttributes()
            // 2. 초기 state 값 설정.
            let initialState = SimpleAttributes.ContentState(
                currentImage: "house",
                currentLevel: 1
            )
            // 3. Acitivity content 생성.
            let content = ActivityContent(
                state: initialState,
                staleDate: nil
            )
            //4. 생성한 Attribute와 Content로 Activity request 호출.
            let activity = try Activity.request(
                attributes: att,
                content: content
            
            )
            // tip. 생성된 Activity는 id를 갖게 된다. 
            print("Activity Successfully added. \(activity.id)")
            return Text("Activity Successfully added. \(activity.id)")
            
        }
        catch {
            print("Failed -- \(error.localizedDescription)")
            return Text("Failed -- \(error.localizedDescription)")
        }
        
        
    }
}

 

결과화면

Lock Screen
Dynamic Island - Compact mode
Dynamic Island - Expand mode

반응형