← Wszystkie wpisy

Środowisko uruchomieniowe watchOS to kontrakt, a nie zadanie w tle

Gatunek: shipped-code. Wpis dokumentuje wzorzec środowiska uruchomieniowego watchOS, który Return stosuje produkcyjnie. Return to medytacyjny licznik czasu w SwiftUI dostępny w App Store; aplikacja na zegarek uruchamia wielocyklowy licznik, który musi nadal odliczać po opuszczeniu nadgarstka przez użytkownika.1 Wzorzec, który przetrwa to ograniczenie, opiera się na WKExtendedRuntimeSession w połączeniu z globalnym delegatem o zasięgu aplikacji. Wszystko inne ginie w momencie, w którym zegarek przechodzi w stan uśpienia.

watchOS to nie iOS z mniejszym ekranem. Model środowiska uruchomieniowego jest inny. iOS daje aplikacji hojny budżet na pierwszym planie i kurczący się, ale realny czas pracy w tle dzięki sesjom audio, aktualizacjom lokalizacji, BGTaskScheduler oraz garści innych mechanizmów.2 watchOS daje aplikacji na pierwszym planie budżet liczony w sekundach po opuszczeniu nadgarstka, a po jego upływie aplikacja jest zawieszana, chyba że podpisała z systemem kontrakt środowiska uruchomieniowego. Nie ma tam mechanizmu typu „po prostu wykonuję sobie zadanie w tle”. Jest „prowadzę trening, sesję uważności, inteligentny budzik, trasę nawigacji lub zadanie monitorowania zdrowia” — i nic poza tym.3

Aplikacją docelową Return na zegarku jest licznik uważności. Kontraktem sesji jest WKBackgroundModes: mindfulness. API środowiska uruchomieniowego to WKExtendedRuntimeSession. Wzorzec, który sprawił, że aplikacja na zegarek przeszła z zepsutej w momencie opuszczenia nadgarstka do przetrwa 25-minutową medytację, opisuje właśnie ten wpis.

TL;DR

  • watchOS nie ma trybu w tle w stylu iOS. Czas działania na pierwszym planie kończy się wkrótce po opuszczeniu nadgarstka, a kontynuują działanie wyłącznie zarejestrowane typy sesji.
  • WKExtendedRuntimeSession to powierzchnia API. Sesja musi zadeklarować swój typ; w przypadku licznika medytacji typ jest deklarowany pośrednio przez WKBackgroundModes: mindfulness w Info.plist.
  • Menedżer sesji musi żyć w zasięgu aplikacji, a nie widoku. Cykl życia widoku w SwiftUI dealokuje obiekty należące do widoku przy nawigacji; zdealokowany delegat sesji to martwa sesja, nawet jeśli sama sesja nadal działa.
  • Wywołania zwrotne WKExtendedRuntimeSessionDelegate to kontrakt: didStart, willExpire, didInvalidateWith. Wywołanie expire uruchamia się przed wymuszeniem unieważnienia przez system; Apple opisuje to jako moment, w którym aplikacja powinna „zakończyć i posprzątać”.
  • Opuszczenie nadgarstka bez aktywnej sesji rozszerzonej wstrzymuje licznik. Opuszczenie nadgarstka z aktywną sesją rozszerzoną pozwala licznikowi działać dalej. Sesja stanowi różnicę między „wdrożonym produktem” a „zepsutym przy drugim użyciu”.

Problem działania w tle, którego watchOS nie rozwiązuje w stylu iOS

Aplikacje iOS sięgają po kilka mechanizmów działania w tle, gdy potrzebują, aby aplikacja działała przy wyłączonym ekranie:2

  • AVAudioSession z kategorią .playback utrzymuje aplikację audio przy życiu podczas odtwarzania muzyki.
  • CLLocationManager z aktualizacjami w tle utrzymuje aplikację nawigacyjną przy życiu wraz z niebieskim paskiem.
  • BGTaskScheduler kolejkuje krótkie zadania konserwacyjne, które system planuje według własnego zegara.
  • Rozszerzenie interfejsu na pierwszym planie (Live Activity, CallKit, PushKit) łączy proces aplikacji z powierzchnią renderowania kontrolowaną przez system.

Żaden z tych mechanizmów nie działa w watchOS w sposób, w jaki można by przypuszczać. Aplikacje na zegarek nie mają tego samego planera zadań w tle. Nie mają trybu AVAudioSession.playback działającego w tle, który utrzymywałby odliczanie licznika w ciszy. Mają jeden strukturalny prymityw na potrzeby „chcę nadal działać po opuszczeniu nadgarstka przez użytkownika”, a tym prymitywem jest WKExtendedRuntimeSession z zadeklarowanym typem sesji.3

Typy sesji obsługiwane przez Apple za pośrednictwem WKBackgroundModes są celowo wąskie:4

  • workout-processing (z HKWorkoutSession dla rzeczywistych treningów)
  • mindfulness (dla liczników medytacji i ćwiczeń oddechowych)
  • self-care (dla rutyn z przewodnikiem)
  • physical-therapy (dla aplikacji terapeutycznych)
  • alarm (dla budzików opartych na czasie)
  • underwater-depth (dla aplikacji do nurkowania i śledzenia głębokości)

Aplikacje, które nie mieszczą się w jednej z tych kategorii, nie mogą używać WKExtendedRuntimeSession, aby działać po opuszczeniu nadgarstka. Aplikacje audio sięgają po kategorię sesji audio mediaPlayback oraz integrację Now Playing na innej ścieżce kodu; aplikacje nawigacyjne korzystają z aktualizacji CLLocationManager w tle. Watch nie jest komputerem ogólnego przeznaczenia; to urządzenie z ograniczeniami baterii, które egzekwuje model środowiska uruchomieniowego.

Licznik medytacji pasuje do mindfulness. Kontrakt: zadeklarować tryb działania w tle w Info.plist, zażądać WKExtendedRuntimeSession, obsłużyć wywołania zwrotne delegata, zakończyć sesję po zakończeniu odliczania. System udziela do około godziny czasu pracy na sesję, przy czym może go skrócić według własnego uznania w warunkach obciążenia termicznego lub niskiego stanu baterii.3

Wzorzec wdrożony w Return

Wzorzec rozpoczyna się od deklaracji w Info.plist:4

<key>WKBackgroundModes</key>
<array>
    <string>mindfulness</string>
</array>

Deklaracja trybu jest tym, co czyni dany typ sesji ważnym. Bez niej wywołanie WKExtendedRuntimeSession().start() kończy się po cichu niepowodzeniem, a aplikacja zawiesza się przy opuszczeniu nadgarstka tak samo, jak aplikacja Watch bez żadnego trybu w tle.

Sam menedżer sesji musi żyć w zasięgu aplikacji. Cykl życia widoku w SwiftUI jest nieprzyjazny dla długo żyjących obiektów ze stanem: @StateObject i @State mają zasięg widoku, który je posiada, a wypchnięcie nawigacyjne zastępujące widok porzuca razem z nim stan. WKExtendedRuntimeSession, którego delegat zostanie zdealokowany w trakcie sesji, nie powoduje awarii; sesja kontynuuje działanie, ale wywołania zwrotne delegata (willExpire, didInvalidateWith) docierają do zwolnionego obiektu, co oznacza, że sprzątanie nigdy nie następuje, co z kolei oznacza, że kolejne wywołanie startSession() uznaje, że nie ma aktywnej sesji, i uruchamia duplikat.

Wzorzec wdrożony to singleton w zasięgu aplikacji. Poniższy fragment przedstawia kształt strukturalny; w środowisku produkcyjnym dodaje się logowanie wewnątrz każdej metody w celu obserwowalności:

import SwiftUI
import WatchKit

final class WatchSessionManager: NSObject, WKExtendedRuntimeSessionDelegate {
    static let shared = WatchSessionManager()

    private var session: WKExtendedRuntimeSession?

    private override init() {
        super.init()
    }

    var isSessionActive: Bool {
        session != nil
    }

    func startSession() {
        guard session == nil else { return }
        let newSession = WKExtendedRuntimeSession()
        newSession.delegate = self
        newSession.start()
        session = newSession
    }

    func endSession() {
        guard let existing = session else { return }
        existing.invalidate()
        session = nil
    }

    // MARK: - WKExtendedRuntimeSessionDelegate

    func extendedRuntimeSessionDidStart(_ session: WKExtendedRuntimeSession) {}

    func extendedRuntimeSessionWillExpire(_ session: WKExtendedRuntimeSession) {
        // Apple's "about to expire / finish and clean up" hook
    }

    func extendedRuntimeSession(
        _ session: WKExtendedRuntimeSession,
        didInvalidateWith reason: WKExtendedRuntimeSessionInvalidationReason,
        error: Error?
    ) {
        self.session = nil
    }
}

Trzy szczegóły dotyczące tego singletona, których dokumentacja nie wyróżnia:

static let shared w połączeniu z @State private var sessionManager = WatchSessionManager.shared na poziomie @main App utrzymuje menedżera przy życiu przez cały cykl życia procesu aplikacji Watch. SwiftUI nie zatrzymuje singletonów tylko dlatego, że posiada je widok; powyższe wiązanie mówi środowisku uruchomieniowemu, aby zachowało referencję. Bez wiązania na poziomie App, ARC może porzucić menedżera, gdy żaden widok go nie trzyma.

Właściwość session jest zabezpieczeniem przed zduplikowanymi sesjami. Licznik z przyciskiem „rozpocznij od nowa” może wywoływać startSession() z wielu ścieżek; sprawdzenie guard session == nil jest blokadą. Dwie równoczesne sesje rozszerzone powodują nieprzewidywalne zachowanie: czasem druga się powiedzie, a pierwsza staje się osierocona, czasem wywołanie startu kończy się po cichu niepowodzeniem. Niezmiennik pojedynczej sesji zapobiega całej tej klasie problemów.

Wywołania zwrotne delegata logują, ale rzadko działają. Wywołanie didStart uruchamia się raz na sesję i jest przydatnym punktem zaczepienia dla obserwowalności; wywołanie willExpire uruchamia się przed wymuszeniem unieważnienia przez system i jest miejscem, w którym Apple oczekuje, że aplikacja „zakończy i posprząta”; wywołanie didInvalidateWith jest miejscem, w którym referencja sesji się zeruje, aby kolejne wywołanie startSession() zadziałało. Wzorzec produkcyjny brzmi: wywołania zwrotne aktualizują stan, maszyna stanowa wykonuje pracę, a nie wywołania zwrotne wykonują pracę bezpośrednio.

Menedżer licznika wywołuje menedżera sesji przy każdej zmianie stanu, która wpływa na to, czy licznik aktywnie odlicza:

final class WatchTimerManager: ObservableObject {
    func start() {
        startExtendedSession()        // -> WatchSessionManager.shared.startSession()
        // ... start the timer state machine ...
    }

    func pause() {
        timer?.invalidate()
        isRunning = false
        endExtendedSession()          // -> WatchSessionManager.shared.endSession()
    }

    func reset() {
        // ... clear timer state ...
        endExtendedSession()
    }

    private func completeCycle() {
        // ... last cycle handling ...
        endExtendedSession()          // ends on final completion
    }
}

Sesja kończy się przy pauzie, przy zresetowaniu i przy zakończeniu ostatniego cyklu. Uzasadnienie produktowe: wstrzymana medytacja nie musi nadal zajmować budżetu czasu uruchomieniowego, jaki system przyznaje w ramach mindfulness; wznowienie z pauzy ponownie pobiera świeżą sesję. Koszt produktowy jest taki, że pauzy zrobionej z opuszczonym nadgarstkiem nie da się wznowić samym podniesieniem ręki; użytkownik musi przywrócić aplikację na pierwszy plan, aby kontynuować. Zysk produktowy polega na tym, że koszt baterii w stanie pauzy spada do zera, a system nie widzi nieaktualnej sesji.

Opuszczenie nadgarstka jest testem

Testowanie watchOS w symulatorze to grzeczna fikcja. Symulator nie egzekwuje modelu środowiska uruchomieniowego po opuszczeniu nadgarstka tak, jak robi to prawdziwy Apple Watch. Symulator utrzymuje aplikację na pierwszym planie tak długo, jak okno symulatora ma fokus; rozszerzona sesja środowiska uruchomieniowego w symulatorze wygląda identycznie jak brak sesji, ponieważ aplikacja na pierwszym planie i tak działa dalej.

Faktyczny test odbywa się na prawdziwym Apple Watch:5

  1. Uruchomić licznik.
  2. Opuścić nadgarstek (lub nacisnąć przycisk boczny, aby zablokować ekran).
  3. Odczekać 30 sekund.
  4. Podnieść nadgarstek z powrotem.

Bez aktywnej rozszerzonej sesji środowiska uruchomieniowego aplikacja zegarka jest zawieszona; stan licznika zostaje zamrożony w momencie opuszczenia nadgarstka i wznawia się od tego zamrożonego stanu. W przypadku 5-minutowej medytacji, podczas której użytkownik zamyka oczy, błąd jest niewidoczny aż do momentu, gdy licznik jest błędny o tyle, ile czasu oczy były zamknięte.

Z aktywną rozszerzoną sesją środowiska uruchomieniowego licznik kontynuuje odliczanie. Podniesienie nadgarstka odsłania licznik na właściwej pozycji upływu czasu. Sygnał dźwiękowy (jeśli licznik odtwarza go na zakończenie) odpala się o właściwym czasie zegarowym, a nie o czasie podniesienia nadgarstka.

Scenariusz opuszczenia nadgarstka był błędem, który Return wdrożył w wersji v1, a załatał w v2. Naprawa polega na powyższym wzorcu singletona; błąd polegał na tym, że instancja WatchSessionManager była trzymana przez widok SwiftUI, który był dealokowany przy wypchnięciu nawigacyjnym. Sesja technicznie działała po stronie systemu, ale delegat został zwolniony; kolejne wywołanie startu sesji było po cichu pustą operacją, ponieważ właściwość session menedżera została ustawiona na obecnie martwym obiekcie. Testy na rzeczywistym urządzeniu ujawniają tę awarię w sekundach. Testy w symulatorze nie ujawniają jej nigdy.

Co naprawdę mówią wywołania zwrotne delegata

WKExtendedRuntimeSessionInvalidationReason wylicza sposoby, w jakie sesja może się zakończyć:6

Powód Kiedy występuje
none Sesja została jawnie unieważniona przez wywołanie invalidate() przez aplikację
sessionInProgress Sesja tego samego typu już działa
expired Osiągnięto narzucony przez system limit czasu
resignedFrontmost Inna aplikacja stała się aplikacją na pierwszym planie podczas trwania sesji
suppressedBySystem System stłumił sesję (niski poziom mocy, presja termiczna)
error Wystąpił nieodwracalny błąd; należy sprawdzić parametr error

Powody, które mają znaczenie dla projektowania produktu:

expired oznacza, że użytkownik dostał pełną sesję, o jaką poprosiłeś. Sesja przebiegła do swojego naturalnego końca. Najdłuższy czas trwania medytacji w Return to 60 minut, co znajduje się dokładnie na granicy tego, co sesje mindfulness zwykle otrzymują. 90-minutowa medytacja rutynowo trafiałaby na expired, a licznik umierałby w połowie sesji. Decyzja produktowa to ograniczenie dostępnych czasów trwania do tego, co model środowiska uruchomieniowego może faktycznie zapewnić.

resignedFrontmost oznacza, że użytkownik otworzył inną aplikację Watch i Twoja sesja przegrała. Użytkownicy zegarka są dobrzy w przesuwaniu do innej aplikacji, a potem zapominaniu o tym. Decyzja produktowa to albo wstrzymanie przy rezygnacji z pierwszego planu (stan zachowany, użytkownik może wrócić), albo zakończenie przy rezygnacji (sesja skończona, użytkownik dostaje sygnał „przerwałeś wcześniej”). Return wybiera wstrzymanie przy rezygnacji, aby użytkownik mógł odebrać telefon w trakcie medytacji i wrócić.

suppressedBySystem to grzeczna wersja stwierdzenia „zegarek jest gorący”. Urządzenie watchOS pod wpływem presji termicznej lub niskiego poziomu baterii może odebrać rozszerzoną sesję środowiska uruchomieniowego nawet bez nadużycia ze strony aplikacji. Menedżer sesji musi obsłużyć ten przypadek z gracją: wyczyścić referencję, wyświetlić nieblokujące ostrzeżenie i nie wchodzić w stan, w którym próbuje zrestartować sesję, której system właśnie odmówił.

Wywołanie willExpire uruchamia się, gdy sesja zbliża się do wygaśnięcia, i jest udokumentowane jako moment, w którym aplikacja powinna „zakończyć i posprzątać”.3 Wywołanie zwrotne to miejsce, w którym aplikacja może zapisać końcowy snapshot stanu, odtworzyć zamykający sygnał audio lub zaprezentować interfejs „sesja wkrótce się skończy”. Return obecnie tylko loguje to wywołanie zwrotne; bogatsze sprzątanie (wpis w dzienniku HealthKit, wyciszenie audio) odbywa się na ścieżkach resetu i ukończenia licznika i znajduje się na liście co zbudowałbym inaczej dla okna willExpire.

Co zbudowałbym inaczej

Dwie rzeczy, gdyby Return powstawał od zera.

Używać HKWorkoutSession dla każdej sesji, której wartość rośnie wraz z integracją z HealthKit. Licznik medytacji znajduje się na granicy między mindfulness a workout-processing. Mindfulness był właściwym wyborem dla v1, ponieważ model danych jest prostszy, a oczekiwanie użytkownika brzmi „to jest medytacja, a nie trening”. HKWorkoutSession zawiera bardziej szczegółową integrację z HealthKit (start sesji, koniec sesji, segmenty, zdarzenia) i zapewnia bogatszy interfejs LiveWorkoutBuilder do gromadzenia danych. Ocena architektoniczna, a nie udokumentowana gwarancja Apple: dla aplikacji, której wartość zależy od szczegółowej telemetrii sesji, ścieżka workout-session obsługuje strukturę, której WKExtendedRuntimeSession nie zapewnia.

Dodać powierzchnię obserwowalności stanu sesji od pierwszego dnia. Pierwsza wersja Return logowała zdarzenia sesji do konsoli. Druga wersja dodała widoczność stanu sesji na urządzeniu na potrzeby debugowania. Trzecia ujawniałaby przełącznik trybu deweloperskiego, który prezentuje historię powodów sesji użytkownikowi, gdy coś pójdzie nie tak, zamiast traktować unieważnienie sesji jak czarną skrzynkę. Środowisko uruchomieniowe watchOS jest nieprzejrzyste; powierzchnia debugowania musi to rekompensować.

Kiedy WKExtendedRuntimeSession jest złą odpowiedzią

Trzy przypadki, w których typ sesji nie pasuje:

Treningi, które wymagają znaczników segmentów, strumieni tętna lub śledzenia aktywnych kalorii. Należy używać HKWorkoutSession bezpośrednio z HKLiveWorkoutBuilder. API Workout to udokumentowana przez Apple ścieżka dla rzeczywistych treningów (a także medytacji w marszu lub forsownej aktywności); WKExtendedRuntimeSession to udokumentowana ścieżka dla sesji innych niż treningi, takich jak uważność czy budziki. Aplikacja medytacyjna nie potrzebuje treningu; aplikacja Couch-to-5K go potrzebuje.

Odtwarzanie audio wymagające powierzchni Now Playing. Należy używać AVAudioSession skonfigurowanej do odtwarzania wraz z uprawnieniami sesji audio watchOS; integracja Now Playing wraz z systemową powierzchnią odtwarzania jest tym, czego chcą aplikacje audio, a ścieżka audio jest oddzielona od WKExtendedRuntimeSession. WKExtendedRuntimeSession nie zapewnia Now Playing ani systemowego routingu audio.

Długotrwała synchronizacja danych bez świadomości użytkownika. Należy używać WKApplicationRefreshBackgroundTask dla okresowych okien odświeżania, które system planuje samodzielnie. Użytkownik nie jest w aplikacji; aplikacja nie musi nadal działać; potrzebuje krótko się obudzić i odświeżyć. Modele zadania w tle i rozszerzonej sesji środowiska uruchomieniowego służą bardzo różnym potrzebom.

Co ten wzorzec oznacza dla aplikacji wdrażanych na watchOS 11+

Trzy wnioski.

  1. Model środowiska uruchomieniowego Watch jest opt-in. Wybierz typ sesji i żyj wewnątrz jego reguł. Aplikacje, które próbują wykonywać „ogólną pracę w tle” w watchOS, przegrają. Wybierz mindfulness, workout-processing, self-care, physical-therapy, alarm lub underwater-depth i zaprojektuj doświadczenie użytkownika wokół budżetu środowiska uruchomieniowego, który niesie ze sobą wybrany typ sesji.

  2. Delegat sesji musi żyć w zasięgu aplikacji. Cykl życia widoku w SwiftUI nie chroni długo żyjących obiektów ze stanem. Singleton static let shared powiązany na poziomie @main App to najmniejszy wzorzec, który przetrwa wypchnięcia nawigacyjne, zastępowanie widoków i normalne zachowanie dealokacji w SwiftUI.

  3. Testuj na prawdziwym sprzęcie. Symulator nie egzekwuje modelu środowiska uruchomieniowego po opuszczeniu nadgarstka. Błąd, którego aplikacja Watch nie może przetestować w symulatorze, to błąd, który dostarczy użytkownikom.

Połącz ten wpis z moimi wcześniejszymi tekstami o tej samej rodzinie aplikacji: wieloplatformowe wdrażanie SwiftUI (Return jest dostępny na iPhone’a, iPada, Watch, Mac i Apple TV); maszyna stanów Live Activities (powierzchnia po stronie iOS dla tego samego licznika); wzorce HealthKit (gdzie sesje uważności Watch trafiają w danych Health użytkownika). Pełen zestaw znajduje się w hubie serii Apple Ecosystem. Szerszy kontekst dotyczący iOS z agentami AI znajduje się w przewodniku po iOS Agent Development.

FAQ

Czym jest rozszerzona sesja środowiska uruchomieniowego watchOS?

Rozszerzona sesja środowiska uruchomieniowego watchOS (WKExtendedRuntimeSession) to API, którego aplikacja Watch używa, aby kontynuować działanie po opuszczeniu nadgarstka przez użytkownika. Sesja musi zadeklarować typ (mindfulness, workout-processing, alarm itd.) za pośrednictwem WKBackgroundModes w Info.plist. Bez aktywnej sesji rozszerzonej watchOS zawiesza aplikację wkrótce po opuszczeniu nadgarstka.

Dlaczego mój licznik watchOS przestaje odliczać, gdy użytkownik opuszcza nadgarstek?

Aplikacja Watch zostaje zawieszona wkrótce po opuszczeniu nadgarstka, chyba że działa aktywna WKExtendedRuntimeSession obsługiwanego typu. Menedżer licznika, który nie uruchamia takiej sesji, zobaczy odcięcie czasu działania w tle, a stan licznika zamrozi się w momencie opuszczenia nadgarstka, dopóki użytkownik ponownie go nie podniesie.

Jaka jest różnica między WKExtendedRuntimeSession a HKWorkoutSession?

WKExtendedRuntimeSession to API rozszerzonego środowiska uruchomieniowego ogólnego przeznaczenia dla sesji innych niż treningi, takich jak mindfulness, alarm czy self-care. HKWorkoutSession to API dla rzeczywistych treningów; integruje się z HealthKit, obsługuje znaczniki segmentów i jest udokumentowaną ścieżką dla medytacji w marszu lub forsownej aktywności. Aplikacje uważności bez telemetrii klasy treningowej używają pierwszego; aplikacje treningowe używają drugiego.

Czy system może odebrać moją rozszerzoną sesję środowiska uruchomieniowego?

Tak. WKExtendedRuntimeSessionInvalidationReason obejmuje expired (osiągnięto systemowy limit czasu), resignedFrontmost (inna aplikacja Watch stała się aplikacją na pierwszym planie) oraz suppressedBySystem (niski poziom mocy lub presja termiczna). Menedżer sesji musi obsłużyć każdy z tych przypadków czysto: referencja się zeruje, stan licznika reaguje odpowiednio, a kolejne wywołanie startu sesji działa poprawnie.

Gdzie powinien żyć menedżer sesji w aplikacji watchOS opartej na SwiftUI?

W zasięgu aplikacji, jako singleton powiązany ze struktury @main App. Stan z zasięgiem widoku w SwiftUI (@State, @StateObject) jest dealokowany przy wypchnięciach nawigacyjnych, zastępowaniu widoków lub przejściu aplikacji w tło. Delegat sesji należący do widoku, który zostaje zwolniony w trakcie sesji, powoduje wyciek referencji sesji i uniemożliwia czyste uruchamianie kolejnych sesji.

Bibliografia


  1. Autorska aplikacja Return, licznik medytacji w SwiftUI opublikowany w App Store 21 kwietnia 2026, dostępny dla iPhone’a, iPada, Maca, Apple Watch i Apple TV. Aplikacja Watch używa WKExtendedRuntimeSession z trybem tła mindfulness dla środowiska uruchomieniowego licznika cykli. 

  2. Apple Developer, „About the background execution sequence”. Mechanizmy działania w tle po stronie iOS (sesje audio, lokalizacja, BGTaskScheduler) i to, jak różnią się od watchOS. 

  3. Apple Developer, „WKExtendedRuntimeSession”. Typy sesji, cykl życia, wywołania zwrotne delegata, limity środowiska uruchomieniowego i klucz WKBackgroundModes w Info.plist. 

  4. Apple Developer, „Information Property List: WKBackgroundModes”. Obsługiwane ciągi typów sesji: workout-processing, mindfulness, self-care, physical-therapy, alarm, underwater-depth

  5. Apple Developer, „Building a watchOS app” oraz wskazówki dotyczące testowania WatchKit. Zachowanie środowiska uruchomieniowego na rzeczywistym urządzeniu nie jest reprodukowalne w symulatorze watchOS; symulator nie egzekwuje zawieszania po opuszczeniu nadgarstka. 

  6. Apple Developer, „WKExtendedRuntimeSessionInvalidationReason”. Przypadki wyliczeniowe: none, sessionInProgress, expired, resignedFrontmost, suppressedBySystem, error

Powiązane artykuły

HealthKit + SwiftUI on iOS 26: Authorization, Sample Types, and Cross-Platform Patterns

Real production patterns from Water (water tracking, HKQuantitySample) and Return (mindful sessions, HKCategorySample). …

17 min czytania

What SwiftUI Is Made Of

SwiftUI is a result-builder DSL on top of a value-typed View tree. Once the substrate is visible, AnyView, Group, and Vi…

17 min czytania

The Cleanup Layer Is the Real AI Agent Market

Charlie Labs pivoted from building agents to cleaning up after them. The AI agent market is moving from generation to pr…

15 min czytania