- 검사가 종료 실행 기기 기준이라 기기별 값이면 교차 사용(아이패드 시작→아이폰 종료)에서 결과가 갈리던 문제 해소 — 값 자체를 모든 기기에서 통일 - SettingsCloudSync: 시작 시 iCloud 값 채택(없으면 로컬 값 시드), 외부 변경·포그라운드 복귀 때 pull, 설정 변경 때 push(동일 값 가드). App Group 저장은 유지(위젯·인텐트 읽기 경로 무변경), CloudKit 스키마·프리미엄 토글과 무관 — ubiquity-kvstore 엔타이틀먼트만 추가 - 설정: 측정 섹션을 나눠 '짧은 기록 무시' 바로 밑에 전 기기 공통 안내 푸터, '장시간 측정 알림'은 기기별 유지 명시. 도움말도 갱신, en/ja 번역(missing 0·stale 0, 실렌더 확인) - whats-new-1.1 3개 언어에 항목 추가, CLAUDE.md §6.8 갱신 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVeduv1eNdXjk1ay4tSgBg
71 lines
3.1 KiB
Swift
71 lines
3.1 KiB
Swift
//
|
|
// SettingsCloudSync.swift
|
|
// Haru_Danim
|
|
//
|
|
// "모든 기기에서 같아야 하는" 설정의 iCloud 키-값 저장소 동기화 (현재: 짧은 기록 무시)
|
|
// - 짧은 기록 검사는 종료를 실행한 기기의 설정을 쓰므로(§6.8), 기기마다 값이 다르면
|
|
// 아이패드에서 시작해 아이폰에서 끝내는 식의 교차 사용에서 결과가 갈렸다 — 값 자체를 맞춘다.
|
|
// - CloudKit 데이터 동기화(프리미엄 + cloudSync 토글)와 별개 저장소라 스키마·심사 절차 없이
|
|
// iCloud 로그인만 되어 있으면 동작한다. 미로그인이면 조용히 로컬 값 유지.
|
|
// - 시작 시: iCloud 값이 있으면 로컬(App Group)에 반영, 없으면 현재 로컬 값을 올려 시드.
|
|
// 이후 외부 변경 알림·포그라운드 복귀 때 당겨오고, 설정 화면의 변경은 push로 올린다.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
@MainActor
|
|
final class SettingsCloudSync {
|
|
static let shared = SettingsCloudSync()
|
|
|
|
/// 동기화 대상 키 — 추가할 설정이 생기면 여기에만 더하면 된다 (Int 값 한정)
|
|
private let syncedKeys = [SettingsKeys.minSessionSeconds]
|
|
private var observers: [any NSObjectProtocol] = []
|
|
|
|
/// 앱 시작 시 1회 호출
|
|
func start() {
|
|
guard observers.isEmpty else { return }
|
|
let kvs = NSUbiquitousKeyValueStore.default
|
|
let center = NotificationCenter.default
|
|
observers.append(center.addObserver(
|
|
forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
|
|
object: kvs, queue: nil
|
|
) { _ in
|
|
Task { @MainActor in SettingsCloudSync.shared.pull(seedIfMissing: false) }
|
|
})
|
|
observers.append(center.addObserver(
|
|
forName: UIApplication.willEnterForegroundNotification,
|
|
object: nil, queue: nil
|
|
) { _ in
|
|
Task { @MainActor in
|
|
NSUbiquitousKeyValueStore.default.synchronize()
|
|
SettingsCloudSync.shared.pull(seedIfMissing: false)
|
|
}
|
|
})
|
|
kvs.synchronize()
|
|
pull(seedIfMissing: true)
|
|
}
|
|
|
|
/// iCloud → 로컬(App Group). 최초 1회는 iCloud에 값이 없으면 현재 로컬 값을 올려
|
|
/// 이후 기기들이 따라오게 한다(먼저 업데이트한 기기의 값으로 통일).
|
|
private func pull(seedIfMissing: Bool) {
|
|
let kvs = NSUbiquitousKeyValueStore.default
|
|
for key in syncedKeys {
|
|
if let remote = kvs.object(forKey: key) as? Int {
|
|
if AppGroup.defaults.object(forKey: key) as? Int != remote {
|
|
AppGroup.defaults.set(remote, forKey: key)
|
|
}
|
|
} else if seedIfMissing, let local = AppGroup.defaults.object(forKey: key) {
|
|
kvs.set(local, forKey: key)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 설정 화면에서 값이 바뀔 때 호출 — 같은 값이면 올리지 않는다(원격 반영의 되울림 방지)
|
|
func push(_ value: Int, forKey key: String) {
|
|
let kvs = NSUbiquitousKeyValueStore.default
|
|
guard kvs.object(forKey: key) as? Int != value else { return }
|
|
kvs.set(value, forKey: key)
|
|
kvs.synchronize()
|
|
}
|
|
}
|