Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 3. Live Activity (ActivityKit, Dynamic Island, 잠금 화면) - UIKit에서 다이나믹 아일랜드 적용 방법 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 3. Live Activity (ActivityKit, Dynamic Island, 잠금 화면) - UIKit에서 다이나믹 아일랜드 적용 방법

jake-kim 2022. 11. 25. 23:22

1. Live Activity (ActivityKit, Dynamic Island, 잠금 화면) - 개념

2. Live Activity (ActivityKit, Dynamic Island, 잠금 화면) - UI 구현 방법

3. Live Activity (ActivityKit, Dynamic Island, 잠금 화면) - UIKit에서 다이나믹 아일랜드 적용 방법

예제를 위한 UIKit 프로젝트 생성

  • Interface > SwiftUI가 아닌 Storyboard 선택

  • info.plist에서 Live Activity 활성화

  • Xcode에서 target 선택

  • Widget Extension 추가

  • 생성된 것 중 필요한 두 가지 파일 확인
    • JakeBundle: body가 있으며 여러 위젯을 노출할때 사용되는 컨테이너 (아래 JakeLiveAcitivty 인스턴스를 여기에 선언)
    • JakeLiveActivity: 라이브 액티비티 (다이나믹 아일랜드, 잠금화면에 들어갈 뷰와 Attribute가 존재)

  • 여기서 JakeBundle의 Target Membership의 UIKit 관련 타겟은 해제

UIKit에서 라이브 액티비티 사용 방법

  • Widget쪽과 UIKit의 인터페이스를 담당할 LiveAcitivtyManager라는 것을 만들어서 사용
    • Targets에 둘 다 체크

  • 싱글톤으로 start(), update(state:), stop() 세 가지 메소드 구현
    • start(): Activity 인스턴스가 존재하지 않으면 생성하여 표출
    • update(state:): acitivity 업데이트
    • stop(): activity 중지
import SwiftUI
import ActivityKit

final class LiveActivityManager: ObservableObject {
  static let shared = LiveActivityManager()
  
  @Published var activity: Activity<JakeAttributes>?
  
  private init() {}
  
  func start() {
    guard activity == nil else { return }
    let attributes = JakeAttributes(name: "jake")
    let contentState = JakeAttributes.ContentState(value: 5)
    
    do {
      let activity = try Activity<JakeAttributes>.request(
        attributes: attributes,
        contentState: contentState
      )
      print(activity)
    } catch {
      print(error)
    }
  }
  
  func update(state: JakeAttributes.ContentState) {
    Task {
      let updateContentState = JakeAttributes.ContentState(value: state.value)
      for activity in Activity<JakeAttributes>.activities {
        await activity.update(using: updateContentState)
      }
    }
  }
  
  func stop() {
    Task {
      for activity in Activity<JakeAttributes>.activities {
        await activity.end(dismissalPolicy: .immediate)
      }
    }
  }
}

사용하는 UIKit 부분

  • LiveActivityManager.shared로 start(), update(), stop() 사용
import UIKit

class ViewController: UIViewController {
  private let startButton = UIButton(type: .system)
  private let updateButton = UIButton(type: .system)
  private let stopButton = UIButton(type: .system)
  private let stackView = UIStackView()

  override func viewDidLoad() {
    super.viewDidLoad()
    
    stackView.axis = .vertical
    stackView.translatesAutoresizingMaskIntoConstraints = false
    startButton.setTitle("Live Activity 시작", for: .normal)
    updateButton.setTitle("Live Activity 업데이트", for: .normal)
    stopButton.setTitle("Live Activity 중지", for: .normal)
    startButton.addTarget(self, action: #selector(start), for: .touchUpInside)
    updateButton.addTarget(self, action: #selector(update), for: .touchUpInside)
    stopButton.addTarget(self, action: #selector(stop), for: .touchUpInside)
    
    view.addSubview(stackView)
    [startButton, updateButton, stopButton]
      .forEach(stackView.addArrangedSubview(_:))
    
    NSLayoutConstraint.activate([
      stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    ])
  }
  
  @objc private func start() {
    LiveActivityManager.shared.start()
  }
  @objc private func update() {
    LiveActivityManager.shared.update(state: .init(value: (0...100).randomElement()!))
  }
  @objc private func stop() {
    LiveActivityManager.shared.stop()
  }
}

* 전체 코드: https://github.com/JK0369/ExLiveActivityInUIKit

 

* 참고

https://github.com/PurpleShrek/Dynamic-Island-UIKit?ref=iosexample.com 

 

Comments