DADAHAE's Log
비싼 장난감 가지고 노는 중 (❁´▽`❁)*✲゚*
[WWDC22] iOS16에서 새로워진 Screen Time API를 알아보자. (What's new in Screen Time API)
WWDC22 What's new in Screen Time API

https://developer.apple.com/videos/play/wwdc2022/110336/

 

What's new in Screen Time API - WWDC22 - Videos - Apple Developer

Find out how you can build apps that help people manage their relationship with their device — all while putting privacy first. We'll...

developer.apple.com

 

 

 

 

 


 

 

Screen Time API?

Screen Time API는 iOS15에서 처음 소개되었다.

이 API는 3가지의 프레임워크로 표현된다. Family Controls, Managed Settings, Device Activity 이다.

 

 

Family Controls

- Screen Time API의 접근 권한 부여 (일종의 게이트역할)

- 자녀 보호 앱이 삭제되는 것을 방지함 (Prevents removal and circumvention)

- 사용자의 개인정보 보호(앱, 웹 사이트 식별에 opaque token 사용)

 

 

Managed Settings

이 프레임워크도 마찬가지로 앱에 제약을 적용할 수 있다. 

- 앱 사용 제한

- 웹 트래픽 필터링

- 앱의 브랜딩과 기능에 맞게 앱과 웹의 제악조건을 걸 수 있다.

 

 

Device Activity

- 앱, 웹의 사용량을 넘어가면 특정 코드가 실행되도록 할 수 있다.

 


 

iOS16에서 업데이트된 Screen Time API

"Worklog"라는 데모 앱으로 새로운 점들을 살펴보자.
해당 앱은 특정 수치들이 충족될 때까지 특정 앱의 사용을 제한하는 앱이다.

 

Screen Time API로 앱 사용에 어떻게 제한을 거는지 알아보도록 하자!

 

Family Controls

- iOS15 : iCloud 승인을 통해서만 자녀의 기기를 승인할 수 있었다.

- iOS16

- 사용자 기기에서 개별 사용자를 승인할 수 있게 되었다. (individual users authorize themselves)

- 하나의 기기에서 여러 앱을 사용할 수 있다??

- iCloud 로그아웃과 앱 삭제에 대한 내적 제한이 적용되지 않는다.

 

새로운 승인 방법을 알아보자! 아래는 Worklog 데모 앱의 코드이다.

// APP: Request Authorization

import SwiftUI
import FamilyControls

@main
struct Worklog: App {
    let center = AuthorizationCenter.shared
    var body: some Scene {
        WindowGroup {
            VStack {..}
                .onAppear {
                    Task {
                        do {
                            try await center.requestAuthorization (for: .individual)
                        } catch {
                            print("Failed to enroll Aniyah with error: \(error)")
                        }
                    }
                }
        }
    }
}

 

  1. 앱이 실행되면 FamilyControls에 대한 승인을 요청해야 한다. (관문)
  2. `AuthorizationCenter.shared`을 사용하여 Worklog 앱이 시작될 때 승인을 요청한다.
  3. 요청 후에는 승인이 되거나(try) 오류가 발생(catch)한다.

 

iPhone에서 Worklog 앱을 처음 실행할 경우, FamilyControls에 대한 승인을 요청한다. 해당 메서드는 try-catch문의 requestAuthorization(for:)이다.

do {
    try await center.requestAuthorization (for: .individual)
} catch {
    print("Failed to enroll Aniyah with error: \(error)")
}

 

이 메서드는 alert 창을 띄워 승인을 요청한다. 허용을 하면 기기의 암호(FaceID, TouchID 등)를 사용하여 인증하는 메세지가 표시된다. 인증이 잘 마무리되면 request- 메서드가 또 호출되어도 경고 메세지가 다시 표시되지 않는다.

 

 

앱이 FamilyControls로 승인되었다. 그러면 iPhone의 설정에서 해당 앱(여기서는 Worklog)에 대한 스위치가 2개 추가된다. 

- Apps with Screen TimeAccess List

- Screen Time Restrictions

나중에는 이 스위치로만 FamilyControls의 앱 승인을 끄고 켤 수 있다.

이렇게 따로 승인을 조절하는게 이번에 새롭게 업데이트된 부분이다 (!!)

 

 

Managed Settings

iOS16에서는 ManagedSettingsStore를 더 사용하기 쉽게 되었따! 그게 몰까잉

-> 현재 사용자가 기기에 설정을 적용하는 데이터 저장소. 설정 값이 저장된 곳이 ManagedSettingsStore이다.

 

iOS15에서는 프로세스 하나당 하나의 ManagedSettingsStore이 허용되었다.

그러나 iOS16에서는 프로세스 하나당 최대 50개까지 만들 수 있다.

단, 지켜져야 하는 점은 각 ManagedSettingsStore는 고유의 이름을 가져야 한다!

- 앱과 앱의 확장 프로그램은 같은 세팅 값을 공유할 수 있다.

- 각 스토어의 세팅을 한번에 제거할 수 있다.

 

Worklog 앱이 실행되고 기기가 승인되고 나면, 아래의 코드가 수행되면서 'gaming'이라는 ManagedSettingsStore을 만든다.

// APP: Setup the default restrictions for our app

import ManagedSettings

extension ManagedSettingsStore. Name {
    static let gaming = Self("gaming")
    func worklogSetup () {
        let gamingCategory = ActivityCategoryToken (...)
        let gamingStore = ManagedSettingsStore (named : •gaming)
        gamingStore.shield.webDomainCategories = .specific([gamingCategory])
    }
}

'gaming' ManagedSettingsStore은 해당 앱이 모든 게임 웹 사이트를 차단하도록 설정되어 있다.

 

 

마찬가지로 SNS앱과 웹 사이트를 차단하는 'social'이라는 ManagedSettingsStore도 만들 수 있다.

// APP: Shield Social category
import ManagedSettings

extension ManagedSettingsStore. Name {
    static let gaming = Self("gaming")
    static let social = Self("social")
}

func worklogSetup () {
    let gamingCategory = ActivityCategoryToken ( ...)
    let gamingStore = Managed$ettingsStore (named: .gaming)
    gamingStore.shield.webDomainCategories = .specific([gamingCategory])
    
    let socialCategory = ActivityCategoryToken ( ...)
    let socialStore = ManagedSettingsStore (named: .social)
    socialStore.shield.applicationCategories = .specific ([socialCategory])
    socialStore.shield.webDomainCategories = .specific([socialCategory])
}

 

근데 SNS 앱 사용을 특정 시간에만 가능하도록 허용하고 싶을 수도 있다. 'Allow for evenings' 버튼을 누르면 오후 5시~8시 사이에만 SNS 앱을 사용할 수 있도록 허용하는 DeviceActivitySchedule을 생성할 수 있다. 아래는 해당 코드이다.

// APP: Schedule Social Media between 5 and 8 PM

import SwiftUI
import DeviceActivity

extension DeviceActivityName {
    static let activity = Self("activity")
}

struct Worklog: App {
    let deviceActivityCenter = DeviceActivityCenter ()
    var body: some Scene {
        VStack {
            Text ("Social Media")
            Button ("Allow for Evenings", action: {
                try? deviceActivityCenter.startMonitoring(.activity,
                    during: DeviceActivitySchedule (
                        intervalStart: DateComponents (hour: 17),
                        intervalEnd: DateComponents (hour: 20),
                        repeats: true
                    )
                )
            })
        }
    }
}

 

오후 5시가 되면 DeviceActivityMonitor가 해당 ManagedSettingsStore인 'social'에 대한 제한을 해제한다. 오후 8시가 지나면 다시 SNS와 웹사이트의 제한을 시작한다. 이렇게 앱 사용 시간을 조절할 수도 있다!

// MONITOR EXTENSION: Handle Social category at start/end of interval

import DeviceActivity
import ManagedSettings

class WorklogMonitor: DeviceActivityMonitor {
    let database = BarkDatabase ( )
    override func intervalDidStart(for activity: DeviceActivityName) {
        super.intervalDidStart(for: activity)
        let socialStore = ManagedSettingsStore (named: .social)
        socialStore.clearAllSettings()
    }
    override func intervalDidEnd(for activity: DeviceActivityName) {
        super.intervalDidEnd (for: activity)
        let socialStore = ManagedSettingsStore (named: .social)
        let socialCategory = database. socialCategoryToken
        socialStore.shield.applicationCategories = .specific([socialCategory])
        socialStore.shield.webDomainCategories = .specific( [socialCategory])
    }
}

 

 

ManagedSettingsStore은 각각 'gaming', 'social'로 이름 붙여 각각 만들어줬다. 그러므로 'social'이라는 이름의 ManagedSettingsStore을 삭제하여도 'gaming'에는 영향을 미치지 않아 게임 사이트에 대한 제한은 유효하다.

 

이게 다 ManagedSettingsStore에 이름을 붙여서 여러 개를 만드는 기능이 추가되었기에 가능한 이야기이다!

 

 

 

Device Activity

iOS15에서는 앱, 웹 사이트에 대한 사용량 허용치와 사용 시간대에 반응했다.

iOS16에서는 앱에서 SwiftUI를 사용하여 완전히 맞춤화된 사용 보고서를 만들 수 있게 되었다. 

또한 사용량 데이터는 확장 프로그램으로 제공되어서 사용자에게 표시될 데이터와 화면에 표현될 방식을 커스텀할 수 있게 되었다!

 

DeviceActivityReport << 사용자에게 완벽한 보안과 사용자 경험을.. 프라이버시를 지켜줌다.

// APP: Top-level view import SwiftUI
import DeviceActivity

extension DeviceActivityReport. Context {
    static let pieChart = Self("Pie Chart")
}

@main
struct Worklog: App {
    private let thisWeek = DateInterval(...)
    @State private var context: DeviceActivityReport.Context = .pieChart
    @State private var filter = DeviceActivityFilter (segment: daily (during: thisWeek))
    
    var body: some Scene {
        WindowGroup {
            GeometryReader { geometry in
                VStack(alignment: leading) {
                    DeviceActivityReport (context: context, filter: filter)
                        .frame (height: geometry.size.height * 0.75)
                }
            }
        }
    }
}

 

 

// REPORT EXTENSION: Configure Custom Device Activity Report

import SwiftUI
import DeviceActivity

struct PieChartReport: DeviceActivityReportScene {
    let context: DeviceActivityReport.Context = .pieChart
    let content: (PieChartView.Configuration) -> PieChartView
    
    func makeConfiguration (representing data: [DeviceActivityData])
    -> PieChartView. Configuration {
        var totalUsageByCategory: [ActivityCategory:TimeInterval]
        totalUsageByCategory = data.map (...)
        
        return PieChartView.Configuration(totalUsageByCategory: totalUsageByCategory)
    }
}

DeviceActivity 프레임워크는 새로 사용량 데이터를 가져올 때마다 makeConfiguration 메서드를 호출하므로 직접 호출할 필요가 없다.

 

 

이제 이 사용량 데이터를 기반으로 하는 파이차트를 화면에 그려보자.

// REPORT EXTENSION: Configure Custom Device Activity Report

import SwiftUI
import DeviceActivity

struct PieChartView: View {
    struct Configuration {
        let totalUsageByCategory: [ActivityCategory:TimeInterval]
    }
    let configuration: Configuration
    var body: some View {
        // A complex view that renders a bar graph based on Aniyah's usage per category.
        PieChart (usage: configuration.totalUsageByCategory)
    }
}

DeviceActivityData로 PieCharView.Configuration이 파이 차트 뷰에 대한 뷰모델의 역할을 수행한다.

 

확장 프로그램의 body에서 DeviceActivityReport를 정의하여 맞춤형 SwiftUI 보고서를 표현할 수 있다.

// REPORT EXTENSION: Draw Custom Device Activity Report

import SwiftUI
import DeviceActivity

@main
struct WorklogReportExtension: DeviceActivityReportExtension {
    var body: some DeviceActivityReportScene {
        PieChartReport { configuration in
            PieChartView (configuration: configuration)
        }
    }
}

 

 

 

쨔쟈룽

 

 

요약.

 

 

 

  Comments,     Trackbacks