# watchOS 11: Workout API, Complications ve Live Activities 2026 Derin Rehber
Apple Watch platformu her geçen yıl daha güçlü bir geliştirici ekosistemi sunuyor. watchOS 11 ile birlikte gelen yeni API'ler, Watch uygulamalarını gerçek anlamda "companion" olmaktan çıkarıp bağımsız, güçlü sağlık ve fitness deneyimlerine dönüştürüyor. Bu rehberde, production ortamında çalışan bir Watch uygulaması geliştirirken karşılaştığım tüm detayları, kod örneklerini ve performans tuzaklarını paylaşıyorum.
💡 Pro Tip: watchOS 11 geliştirirken her zaman gerçek donanım üzerinde test edin. Simülatör, Always-On display davranışını, sensör verisini ve Double Tap gesture'ı tam olarak simüle edemiyor. Erken aşamada gerçek cihaz testine yatırım yapın.
İçindekiler
- Workout API ve HKWorkoutBuilder Mimarisi
- Custom Workout Types ve Metrics
- Double Tap Gesture Entegrasyonu
- Smart Stack Widget Algoritması
- Live Activities on Watch
- Complications: WidgetKit vs CLKComplicationTimelineEntry
- Always-On Display Optimizasyonu
- Background Tasks ve Limit Yönetimi
- HealthKit Sample Batching
- Performance ve Pil Optimizasyonu
1. Workout API ve HKWorkoutBuilder Mimarisi
watchOS 11, HKWorkoutBuilder API'sini köklü biçimde yeniledi. Artık workout streaming, anlık metrik güncellemeleri ve custom workout type tanımlamaları çok daha esnek. Temelden başlayalım.
swift
1import HealthKit2import WorkoutKit3 4class WorkoutManager: NSObject, ObservableObject {5 private let healthStore = HKHealthStore()6 private var workoutBuilder: HKWorkoutBuilder?7 private var workoutSession: HKWorkoutSession?8 9 @Published var heartRate: Double = 010 @Published var activeCalories: Double = 011 @Published var elapsedTime: TimeInterval = 012 @Published var workoutState: HKWorkoutSessionState = .notStarted13 14 // watchOS 11: Yeni streaming delegate15 private var liveWorkoutBuilder: HKLiveWorkoutBuilder?16 17 func startWorkout(type: HKWorkoutActivityType) async throws {18 let configuration = HKWorkoutConfiguration()19 configuration.activityType = type20 configuration.locationType = .outdoor21 22 // watchOS 11: Session ve builder'ı aynı anda oluştur23 let session = try HKWorkoutSession(24 healthStore: healthStore,25 configuration: configuration26 )27 let builder = session.associatedWorkoutBuilder()28 29 // watchOS 11: Veri kaynakları30 builder.dataSource = HKLiveWorkoutDataSource(31 healthStore: healthStore,32 workoutConfiguration: configuration33 )34 35 self.workoutSession = session36 self.liveWorkoutBuilder = builder as? HKLiveWorkoutBuilder37 38 session.delegate = self39 builder.delegate = self40 41 // watchOS 11: startActivity ile başlat42 let startDate = Date()43 session.startActivity(with: startDate)44 try await builder.beginCollection(at: startDate)45 }46 47 func pauseWorkout() {48 workoutSession?.pause()49 }50 51 func resumeWorkout() {52 workoutSession?.resume()53 }54 55 func endWorkout() async throws {56 guard let session = workoutSession,57 let builder = liveWorkoutBuilder else { return }58 59 let endDate = Date()60 session.end()61 62 // Builder'ı kapat ve workout'u kaydet63 try await builder.endCollection(at: endDate)64 let workout = try await builder.finishWorkout()65 66 print("Workout saved: \(workout.uuid)")67 }68}69 70// MARK: - HKWorkoutSessionDelegate71extension WorkoutManager: HKWorkoutSessionDelegate {72 func workoutSession(73 _ workoutSession: HKWorkoutSession,74 didChangeTo toState: HKWorkoutSessionState,75 from fromState: HKWorkoutSessionState,76 date: Date77 ) {78 DispatchQueue.main.async {79 self.workoutState = toState80 }81 }82 83 func workoutSession(84 _ workoutSession: HKWorkoutSession,85 didFailWithError error: Error86 ) {87 print("Workout session error: \(error)")88 }89}90 91// MARK: - HKLiveWorkoutBuilderDelegate92extension WorkoutManager: HKLiveWorkoutBuilderDelegate {93 func workoutBuilder(94 _ workoutBuilder: HKLiveWorkoutBuilder,95 didCollectDataOf collectedTypes: Set<HKSampleType>96 ) {97 for type in collectedTypes {98 guard let quantityType = type as? HKQuantityType else { continue }99 100 let statistics = workoutBuilder.statistics(for: quantityType)101 102 DispatchQueue.main.async {103 self.updateMetrics(statistics: statistics, type: quantityType)104 }105 }106 }107 108 private func updateMetrics(109 statistics: HKStatistics?,110 type: HKQuantityType111 ) {112 switch type {113 case HKQuantityType(.heartRate):114 let bpm = statistics?.mostRecentQuantity()?.doubleValue(115 for: HKUnit.count().unitDivided(by: .minute())116 ) ?? 0117 heartRate = bpm118 119 case HKQuantityType(.activeEnergyBurned):120 let calories = statistics?.sumQuantity()?.doubleValue(121 for: .kilocalorie()122 ) ?? 0123 activeCalories = calories124 125 default:126 break127 }128 }129 130 func workoutBuilderDidCollectEvent(131 _ workoutBuilder: HKLiveWorkoutBuilder132 ) {133 // Workout event'lerini handle et (lap, pause, segment, etc.)134 let events = workoutBuilder.workoutEvents135 print("Total events: \(events.count)")136 }137}Bu yapı, gerçek zamanlı metrik akışını sağlıyor. watchOS 11'de HKLiveWorkoutBuilder, önceki versiyonlara kıyasla çok daha az batarya tüketimiyle çalışıyor çünkü internal polling mekanizması yerine event-driven bir mimari kullanıyor.
2. Custom Workout Types ve Metrics
watchOS 11, önceden tanımlı workout türlerinin ötesinde custom metrik tanımlamaya imkân veriyor. Özellikle spor uygulamaları için bu kritik bir özellik.
swift
1import WorkoutKit2 3// Custom workout metriği tanımlama4struct CustomWorkoutMetric {5 let identifier: String6 let unit: HKUnit7 let displayName: String8 9 static let swimmingPace = CustomWorkoutMetric(10 identifier: "com.app.swimmingPace",11 unit: HKUnit.second().unitDivided(by: .meter()),12 displayName: "Pace"13 )14 15 static let powerOutput = CustomWorkoutMetric(16 identifier: "com.app.powerOutput",17 unit: .watt(),18 displayName: "Power"19 )20}21 22// Custom workout configuration23class AdvancedWorkoutConfigurator {24 25 func createCyclingWorkout() -> WorkoutPlan {26 // watchOS 11: WorkoutPlan API27 let warmup = WorkoutStep(28 goal: .time(10, .minutes),29 displayName: "Warm Up"30 )31 32 let mainSet = WorkoutStep(33 goal: .time(45, .minutes),34 displayName: "Main Set",35 alert: HeartRateZoneAlert(36 target: .zone(.aerobic),37 metric: .heartRate38 )39 )40 41 let cooldown = WorkoutStep(42 goal: .time(5, .minutes),43 displayName: "Cool Down"44 )45 46 let composition = WorkoutComposition(47 steps: [warmup, mainSet, cooldown]48 )49 50 return WorkoutPlan(51 composition: composition,52 activity: .cycling,53 location: .outdoor54 )55 }56 57 // Interval workout oluşturma58 func createIntervalWorkout(59 intervals: Int,60 workDuration: TimeInterval,61 restDuration: TimeInterval62 ) -> WorkoutPlan {63 var steps: [WorkoutStep] = []64 65 let warmup = WorkoutStep(66 goal: .time(5, .minutes),67 displayName: "Warm Up"68 )69 steps.append(warmup)70 71 for i in 1...intervals {72 let workStep = WorkoutStep(73 goal: .time(workDuration, .seconds),74 displayName: "Interval \(i)",75 alert: HeartRateZoneAlert(76 target: .zone(.anaerobic),77 metric: .heartRate78 )79 )80 81 let restStep = WorkoutStep(82 goal: .time(restDuration, .seconds),83 displayName: "Rest \(i)"84 )85 86 steps.append(contentsOf: [workStep, restStep])87 }88 89 let cooldown = WorkoutStep(90 goal: .time(5, .minutes),91 displayName: "Cool Down"92 )93 steps.append(cooldown)94 95 return WorkoutPlan(96 composition: WorkoutComposition(steps: steps),97 activity: .running,98 location: .outdoor99 )100 }101}Custom workout metriklerini HealthKit'e kaydetmek için HKQuantityType ile custom identifier kullanmanız gerekiyor. Ancak dikkat: App Store review ekibi, kendi oluşturduğunuz metrik tiplerinin HealthKit guidelines'a uygun olduğunu doğruluyor.
3. Double Tap Gesture Entegrasyonu
Apple Watch Series 9 ve Ultra 2 ile gelen Double Tap gesture, watchOS 11'de gelişmiş bir API'ye kavuştu. Artık WKInterfaceHandGestureProvider kullanmak yerine daha temiz bir SwiftUI entegrasyonu mevcut.
swift
1import SwiftUI2import WatchKit3 4struct WorkoutControlView: View {5 @StateObject private var workoutManager = WorkoutManager()6 @State private var showingControls = false7 8 var body: some View {9 ZStack {10 // Ana metrik görünümü11 WorkoutMetricsView(manager: workoutManager)12 13 if showingControls {14 WorkoutControlsOverlay(manager: workoutManager)15 .transition(.opacity.combined(with: .scale))16 }17 }18 // watchOS 11: Double Tap için yeni modifier19 .handGestureShortcut(.primaryAction) {20 withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {21 handleDoubleTap()22 }23 }24 }25 26 private func handleDoubleTap() {27 switch workoutManager.workoutState {28 case .running:29 workoutManager.pauseWorkout()30 case .paused:31 workoutManager.resumeWorkout()32 case .notStarted:33 showingControls.toggle()34 default:35 break36 }37 38 // Haptic feedback39 WKInterfaceDevice.current().play(.click)40 }41}42 43// watchOS 11: Gesture provider doğrudan SwiftUI entegrasyonu44struct WorkoutMetricsView: View {45 @ObservedObject var manager: WorkoutManager46 47 var body: some View {48 VStack(spacing: 12) {49 // Heart rate büyük gösterim50 VStack(spacing: 4) {51 Text("\(Int(manager.heartRate))")52 .font(.system(size: 56, weight: .bold, design: .rounded))53 .foregroundStyle(.red)54 .contentTransition(.numericText())55 .animation(.spring, value: manager.heartRate)56 57 Text("BPM")58 .font(.caption)59 .foregroundStyle(.secondary)60 }61 62 // Kalori63 HStack(spacing: 20) {64 MetricItem(65 value: "\(Int(manager.activeCalories))",66 unit: "CAL",67 color: .orange68 )69 70 MetricItem(71 value: formatTime(manager.elapsedTime),72 unit: "TIME",73 color: .cyan74 )75 }76 }77 .padding()78 }79 80 private func formatTime(_ interval: TimeInterval) -> String {81 let hours = Int(interval) / 360082 let minutes = (Int(interval) % 3600) / 6083 let seconds = Int(interval) % 6084 85 if hours > 0 {86 return String(format: "%d:%02d:%02d", hours, minutes, seconds)87 }88 return String(format: "%02d:%02d", minutes, seconds)89 }90}91 92struct MetricItem: View {93 let value: String94 let unit: String95 let color: Color96 97 var body: some View {98 VStack(spacing: 2) {99 Text(value)100 .font(.system(size: 22, weight: .semibold, design: .rounded))101 .foregroundStyle(color)102 .contentTransition(.numericText())103 Text(unit)104 .font(.caption2)105 .foregroundStyle(.secondary)106 }107 }108}Double Tap, kullanıcı deneyiminde büyük bir fark yaratıyor. Özellikle koşu sırasında telefona veya saate dokunmadan workout'u pause/resume etmek çok değerli. Test ederken dikkat etmeniz gereken nokta: Double Tap gesture, sistem tarafından da kullanılıyor (notification dismiss gibi), bu yüzden gesture conflict yönetimi önemli.
4. Smart Stack Widget Algoritması
watchOS 10 ile gelen Smart Stack, watchOS 11'de daha akıllı hale geldi. Sistem, hangi widget'ı ne zaman öne çıkaracağını belirlemek için Siri Intelligence kullanıyor. Siz de uygulamanızın bu algoritmaya dahil olmasını sağlayabilirsiniz.
Smart Stack sıralamasını etkileyen faktörler:
Contextual relevance: Uygulamanız belirli bir aktiviteyle (sabah koşusu, akşam egzersizi) ilişkiliyse sistem bunu öğreniyor. Bu ilişkiyi AppIntent ile açıkça bildirmek performansı artırıyor.
Widget refresh frequency: Çok sık refresh, Smart Stack sıralamasını olumsuz etkiliyor. watchOS 11'de widget refresh budget system, widget'larınızın "değer üretip üretmediğini" takip ediyor.
Relevance provider: TimelineEntryRelevance struct'ını doğru kullanmak kritik.
swift
1import WidgetKit2import SwiftUI3 4struct WorkoutWidgetEntry: TimelineEntry {5 let date: Date6 let heartRate: Int7 let activeCalories: Int8 let workoutState: String9 let relevance: TimelineEntryRelevance?10}11 12struct WorkoutWidgetProvider: TimelineProvider {13 14 func placeholder(in context: Context) -> WorkoutWidgetEntry {15 WorkoutWidgetEntry(16 date: Date(),17 heartRate: 142,18 activeCalories: 450,19 workoutState: "Running",20 relevance: nil21 )22 }23 24 func getSnapshot(25 in context: Context,26 completion: @escaping(WorkoutWidgetEntry) -> Void27 ) {28 let entry = fetchCurrentWorkoutData()29 completion(entry)30 }31 32 func getTimeline(33 in context: Context,34 completion: @escaping(Timeline<WorkoutWidgetEntry>) -> Void35 ) {36 var entries: [WorkoutWidgetEntry] = []37 let currentDate = Date()38 39 // Aktif workout varsa yüksek relevance40 let isWorkoutActive = WorkoutDataStore.shared.isWorkoutActive41 42 for minuteOffset in 0..<15 {43 let entryDate = Calendar.current.date(44 byAdding: .minute,45 value: minuteOffset,46 to: currentDate47 )!48 49 // watchOS 11: Relevance skorunu dinamik ayarla50 let relevanceScore: Float = isWorkoutActive ? 1.0 : 0.351 let duration: TimeInterval = isWorkoutActive ? 60 : 30052 53 let relevance = TimelineEntryRelevance(54 score: relevanceScore,55 duration: duration56 )57 58 let entry = WorkoutWidgetEntry(59 date: entryDate,60 heartRate: WorkoutDataStore.shared.currentHeartRate,61 activeCalories: WorkoutDataStore.shared.currentCalories,62 workoutState: isWorkoutActive ? "Active" : "Ready",63 relevance: relevance64 )65 entries.append(entry)66 }67 68 // Workout aktifse sık refresh, değilse seyrek69 let refreshPolicy: TimelineReloadPolicy = isWorkoutActive70 ? .after(Date().addingTimeInterval(60))71 : .after(Date().addingTimeInterval(900))72 73 let timeline = Timeline(entries: entries, policy: refreshPolicy)74 completion(timeline)75 }76 77 private func fetchCurrentWorkoutData() -> WorkoutWidgetEntry {78 WorkoutWidgetEntry(79 date: Date(),80 heartRate: WorkoutDataStore.shared.currentHeartRate,81 activeCalories: WorkoutDataStore.shared.currentCalories,82 workoutState: WorkoutDataStore.shared.isWorkoutActive ? "Active" : "Ready",83 relevance: TimelineEntryRelevance(score: 0.5, duration: 120)84 )85 }86}5. Live Activities on Watch
watchOS 11, iPhone'daki Live Activities'i Watch'a taşıdı. Bu özellik, uygulamanız arka planda veya kapalıyken bile dinamik bilgi göstermeyi sağlıyor.
Live Activities Watch entegrasyonu için ActivityKit kullanılıyor ancak Watch'a özgü boyut kısıtlamaları var. Watch için ayrı bir ActivityContent layout tasarlamanız gerekiyor.
Kritik nokta: Watch Live Activity, iPhone'dan bağımsız çalışmıyor. iPhone'da başlatılan bir Live Activity, Watch'ta otomatik görünüyor ancak Watch-only Live Activity başlatmak için iPhone uygulamasının da çalışıyor olması gerekiyor. Bu, background task bütçenizi etkiliyor.
6. Complications: WidgetKit vs CLKComplicationTimelineEntry
watchOS 9'dan itibaren WidgetKit tabanlı complications öneriliyor ancak bazı watch face'lerde hâlâ CLKComplication API gerekiyor. 2026 itibarıyla hangi yaklaşımı kullanacağınızı belirleyen tablo şu:
WidgetKit Complications (Tercih edilmeli):
- Modular, Infograph, Infograph Modular, Graphic Corner, Graphic Bezel watch face'lerinde çalışıyor
- SwiftUI ile tasarlanıyor, animasyon desteği var
- Smart Stack ile entegre, relevance API'si mevcut
- watchOS 9+ zorunlu
CLKComplication (Legacy):
- Tüm watch face'lerde çalışıyor
- Timeline-based refresh, predefined templates
- watchOS 2'den beri mevcut, geriye dönük uyumluluk için gerekli
Production uygulamalar için her iki sistemi de desteklemek öneriliyor. WidgetKit complication'ı primary, CLK'yı fallback olarak kullanın.
7. Always-On Display Optimizasyonu
Apple Watch Series 4 ve üstü ile Ultra serisi, Always-On Display (AOD) destekliyor. watchOS 11'de AOD optimizasyonu için backgroundRefreshMode API'si kritik rol oynuyor.
AOD modunda dikkat edilmesi gerekenler:
- Animasyonları durdur veya yavaşlat
- Parlak renkler yerine düşük ışıklı paletler kullan
- Hassas bilgileri gizle (privacy mode)
- Güncelleme sıklığını azalt
swift
1import SwiftUI2import WatchKit3 4struct WorkoutAODView: View {5 @Environment(\.isLuminanceReduced) private var isLuminanceReduced6 @ObservedObject var manager: WorkoutManager7 8 var body: some View {9 ZStack {10 // AOD arkaplanı her zaman siyah11 Color.black.ignoresSafeArea()12 13 if isLuminanceReduced {14 // Always-On mod: minimal görünüm15 AODMinimalView(manager: manager)16 } else {17 // Normal mod: tam görünüm18 WorkoutMetricsView(manager: manager)19 }20 }21 // watchOS 11: AOD refresh rate kontrolü22 .onChange(of: isLuminanceReduced) { _, reduced in23 if reduced {24 // AOD modunda yüksek frekans güncellemelerini durdur25 manager.reduceUpdateFrequency()26 } else {27 // Normal moda dön28 manager.restoreUpdateFrequency()29 }30 }31 }32}33 34struct AODMinimalView: View {35 @ObservedObject var manager: WorkoutManager36 37 var body: some View {38 VStack(spacing: 8) {39 // Sadece kritik metrikler, düşük parlaklık40 Text("\(Int(manager.heartRate))")41 .font(.system(size: 48, weight: .bold, design: .rounded))42 // AOD için beyaz değil, grimsI43 .foregroundStyle(.white.opacity(0.85))44 45 Text("BPM")46 .font(.caption)47 .foregroundStyle(.white.opacity(0.5))48 49 Divider()50 .overlay(.white.opacity(0.2))51 52 Text(formatElapsed(manager.elapsedTime))53 .font(.system(size: 20, weight: .medium, design: .rounded))54 .foregroundStyle(.white.opacity(0.7))55 }56 .padding()57 }58 59 private func formatElapsed(_ interval: TimeInterval) -> String {60 let minutes = Int(interval) / 6061 let seconds = Int(interval) % 6062 return String(format: "%02d:%02d", minutes, seconds)63 }64}65 66// WorkoutManager'a AOD desteği67extension WorkoutManager {68 private var normalUpdateInterval: TimeInterval { 1.0 }69 private var aodUpdateInterval: TimeInterval { 5.0 }70 71 func reduceUpdateFrequency() {72 // Timer'ı yavaşlat73 updateTimer?.invalidate()74 updateTimer = Timer.scheduledTimer(75 withTimeInterval: aodUpdateInterval,76 repeats: true77 ) { _ in78 Task { @MainActor in79 // Minimal güncelleme80 self.updateElapsedTime()81 }82 }83 }84 85 func restoreUpdateFrequency() {86 updateTimer?.invalidate()87 updateTimer = Timer.scheduledTimer(88 withTimeInterval: normalUpdateInterval,89 repeats: true90 ) { _ in91 Task { @MainActor in92 self.updateAllMetrics()93 }94 }95 }96}AOD'de en sık yapılan hata, normal görünümdeki animasyonları ve renkleri olduğu gibi bırakmak. Bu hem pil ömrünü ciddi ölçüde etkiliyor hem de Apple'ın HIG kurallarına aykırı. Review sırasında reddedilme nedeni olabiliyor.
8. Background Tasks ve Limit Yönetimi
watchOS, background task'ları çok kısıtlı bir bütçeyle yönetiyor. watchOS 11'de bu bütçe biraz genişledi ancak hâlâ çok dikkatli kullanılması gerekiyor.
Background refresh budget: Sistem, günlük ne kadar background refresh hakkınız olduğuna kullanım pattern'lerinize göre karar veriyor. Kullanıcının uygulamanızı ne sıklıkla açtığı, hangi saatlerde aktif olduğu gibi faktörler bu bütçeyi etkiliyor.
WKBackgroundTask türleri:
WKApplicationRefreshBackgroundTask: UI güncellemeleri içinWKURLSessionRefreshBackgroundTask: Arka plan ağ istekleri içinWKWatchConnectivityRefreshBackgroundTask: iPhone ile senkronizasyon içinWKSnapshotRefreshBackgroundTask: Dock snapshot güncellemesi için
Her task için setTaskCompleted() çağırmak şart. Çağırmazsanız sistem uygulamanızın background task bütçesini sıfıra düşürebilir.
9. HealthKit Sample Batching
HealthKit'e sık aralıklarla tek tek sample kaydetmek hem performans hem de pil açısından verimsiz. Bunun yerine batch kayıt kullanın.
swift
1class HealthKitBatchManager {2 private let healthStore = HKHealthStore()3 private var pendingSamples: [HKSample] = []4 private let batchSize = 505 private let flushInterval: TimeInterval = 306 private var flushTimer: Timer?7 8 init() {9 startFlushTimer()10 }11 12 func addHeartRateSample(_ bpm: Double, at date: Date) {13 let heartRateType = HKQuantityType(.heartRate)14 let unit = HKUnit.count().unitDivided(by: .minute())15 let quantity = HKQuantity(unit: unit, doubleValue: bpm)16 17 let sample = HKQuantitySample(18 type: heartRateType,19 quantity: quantity,20 start: date,21 end: date,22 metadata: [23 HKMetadataKeyWasUserEntered: false,24 HKMetadataKeyDeviceManufacturerName: "Apple"25 ]26 )27 28 pendingSamples.append(sample)29 30 if pendingSamples.count >= batchSize {31 Task {32 await flushSamples()33 }34 }35 }36 37 func addCalorieSample(_ calories: Double, start: Date, end: Date) {38 let calorieType = HKQuantityType(.activeEnergyBurned)39 let quantity = HKQuantity(unit: .kilocalorie(), doubleValue: calories)40 41 let sample = HKQuantitySample(42 type: calorieType,43 quantity: quantity,44 start: start,45 end: end46 )47 48 pendingSamples.append(sample)49 }50 51 private func startFlushTimer() {52 flushTimer = Timer.scheduledTimer(53 withTimeInterval: flushInterval,54 repeats: true55 ) { _ in56 Task {57 await self.flushSamples()58 }59 }60 }61 62 func flushSamples() async {63 guard !pendingSamples.isEmpty else { return }64 65 let samplesToSave = pendingSamples66 pendingSamples.removeAll()67 68 do {69 try await healthStore.save(samplesToSave)70 print("Saved \(samplesToSave.count) samples to HealthKit")71 } catch {72 // Başarısız olursa tekrar kuyruğa ekle73 pendingSamples.insert(contentsOf: samplesToSave, at: 0)74 print("HealthKit save failed: \(error)")75 }76 }77 78 deinit {79 flushTimer?.invalidate()80 // Son samples"i senkron flush et81 Task {82 await flushSamples()83 }84 }85}Bu batch manager yaklaşımı, HealthKit write işlemlerini ciddi ölçüde optimize ediyor. Production'da 30 saniyelik interval, çoğu kullanım senaryosu için ideal denge noktası.
10. Performance ve Pil Optimizasyonu
watchOS uygulamalarında pil ve performans optimizasyonu, App Store başarısının kritik bir parçası. Kullanıcı review'larında "pil tüketiyor" şikayeti, uygulamanın kötü rating almasının başlıca nedeni.
Temel kurallar:
WKExtendedRuntimeSessionsadece gerçekten ihtiyaç duyulan durumlarda kullanın- Core Location updates'i mümkün olan en düşük accuracy ile isteyin
- HKAnchoredObjectQuery yerine workout sırasında builder'ın sağladığı dataSource'u tercih edin
- View güncellemelerini
@MainActorile UI thread'e sınırlayın - Gereksiz
@Publishedkullanımından kaçının, sadece gerçekten UI değişikliğine yol açan state'leri publish edin
watchOS 11 spesifik: Yeni backgroundRefreshMode: .ultraLowPower modu, Always-On display sırasında arka plan hesaplamalarını %70'e kadar azaltabiliyor. Workout uygulamaları için bu mod varsayılan tercih olmalı.
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
Okuyucu Ödülü
Simülatör sınırlamaları için geliştirme sırasında kullanabileceğiniz pratik yöntemler: - **Heart rate simülasyonu:** `HKWorkoutBuilder` delegate metodlarını mock data ile manuel tetikleyin - **Double Tap:** Simülatörde çalışmaz; UI test target icinde gesture recognizer doğrudan tetikleyin - **AOD testi:** `isLuminanceReduced` için SwiftUI preview'de `.isLuminanceReduced` environment değerini `true` olarak set edin
Sonuç
watchOS 11, Apple Watch platformunu gerçek anlamda bağımsız ve güçlü bir geliştirici ekosistemi haline getiriyor. Workout API'sinin yenilenmesi, Double Tap'in daha iyi entegrasyonu ve AOD optimizasyon araçları, 2026 itibarıyla Watch-first uygulamalar geliştirmeyi mümkün kılıyor.
En kritik ders: watchOS geliştirme, iOS geliştirmenin küçültülmüş versiyonu değil. Pil, background budget, sensor access gibi kısıtlamalar tamamen farklı bir mimari yaklaşım gerektiriyor. Bu kısıtları tasarımın merkezine koyarak başladığınızda, hem daha iyi uygulamalar üretiyorsunuz hem de App Store review süreçleri çok daha sorunsuz geçiyor.
İlgili Yazılar
- Apple Vision Pro: 1 Yıllık Developer Deneyimi
- iOS 19 Beta: Developer Perspektifinden Yenilikler
- SwiftUI vs UIKit 2026: Yeni Proje Karar Rehberi
- Swift 6 Neler Yeni?
- visionOS 2: Spatial Computing ile Production App Geliştirme

