Wymuszona aktualizacja aplikacji iOS
Aplikacja iOS sprawdza przy starcie, czy użytkownik ma najnowszą wersję z App Store. Jeżeli nie — zamiast ekranu aplikacji pokazuje się komunikat „Zaktualizuj aplikację" z przyciskiem prowadzącym prosto do App Store. Nie da się go pominąć: dopuszczalna jest wyłącznie wersja aktualna.
👤 Instrukcja dla użytkownika
Co widzi klient
Po wypuszczeniu nowej wersji do App Store klient, który jej jeszcze nie pobrał, przy najbliższym uruchomieniu aplikacji zobaczy pełnoekranowy komunikat:
- tytuł Zaktualizuj aplikację i wyjaśnienie, że jego wersja jest nieaktualna,
- numery wersji: zainstalowana i najnowsza,
- sekcja Co nowego — dokładnie ta sama lista zmian, którą wpisujemy w App Store Connect przy wydaniu,
- przycisk Aktualizuj w App Store, który otwiera kartę aplikacji w App Store.
Po aktualizacji i ponownym uruchomieniu aplikacja działa normalnie — komunikat znika sam, nie trzeba nic klikać ani się przelogowywać.
Kogo to dotyczy
| Gdzie | Czy blokuje |
|---|---|
| Aplikacja iOS (App Store) | Tak — poniżej najnowszej wersji ekran jest zablokowany. |
| TestFlight | Nie — buildy testowe mają numer wyższy lub równy sklepowemu. |
| Android (aplikacja z Play) | Nie — to powłoka TWA, treść jest webowa i aktualizuje się sama. |
| Przeglądarka (klient, panel) | Nie — sprawdzenie w ogóle się nie uruchamia. |
Co zrobić po wypuszczeniu wydania
- Wypuść wersję do App Store (
yarn ios:release, potem zatwierdzenie wydania w App Store Connect — patrz Wydanie aplikacji iOS). - Odczekaj, aż wydanie faktycznie pojawi się w sklepie. Blokada włącza się samoczynnie w ciągu ok. godziny od tego momentu (tyle trzyma się cache).
- Nie trzeba nic wdrażać ani przełączać w panelu — numer najnowszej wersji pobierany jest z App Store.
:::warning Blokada dotyczy wszystkich naraz Od chwili, gdy App Store poda nową wersję, każdy klient ze starszą aplikacją zobaczy ekran aktualizacji. Nie wypuszczaj wydania tuż przed zajęciami, na które klienci muszą się zapisać, jeżeli nie masz pewności co do stabilności buildu. Awaryjny wyłącznik opisany jest niżej. :::
🔧 Dokumentacja techniczna
Przepływ
Elementy
| Plik | Rola |
|---|---|
lib/app-update/version.ts | Porównanie wersji segment po segmencie (1.10 > 1.9, 1.1 == 1.1.0). |
lib/app-update/app-store.ts | Odpytanie iTunes Lookup API, cache revalidate: 3600, timeout 8 s. |
lib/app-update/types.ts | Kontrakt odpowiedzi AppVersionResponse. |
app/api/public/app-version/route.ts | Publiczny endpoint GET, Cache-Control: public, max-age=900. |
components/app-update-gate.tsx | Pełnoekranowa blokada, montowana w obu gałęziach app/layout.tsx. |
messages/pl.json, messages/en.json | Przestrzeń appUpdate (w ALWAYS_NAMESPACES, więc dostępna na każdej stronie). |
Skąd bierze się numer wersji
Publiczne iTunes Lookup API (https://itunes.apple.com/lookup?bundleId=...)
zwraca dla identyfikatora pakietu dev.workers.dtmsoftwares.dmt-cms.twa wersję
aktualnie opublikowaną w App Store, jej opis zmian, datę wydania i link do karty
aplikacji. Nie wymaga klucza ani podpisu JWT — w odróżnieniu od App Store Connect
API, którego klucz mamy tylko do wysyłki buildów.
Wersję zainstalowaną podaje App.getInfo() z @capacitor/app, czyli
CFBundleShortVersionString (MARKETING_VERSION z projektu Xcode).
Wersji minimalnej nie konfigurujemy nigdzie — wymagana jest zawsze ta ze sklepu.
Zachowanie awaryjne
Każdy błąd — brak sieci, timeout, nieoczekiwana odpowiedź Apple, pusty wynik
lookupu — kończy się { enforced: false } i brakiem blokady. Niedostępność
Apple nie może zamknąć klientom aplikacji.
Awaryjny wyłącznik: zmienna środowiskowa workera klienta
IOS_FORCE_UPDATE_ENABLED=false
wyłącza mechanizm całkowicie (endpoint zwraca wtedy enforced: false bez
odpytywania Apple). Domyślnie mechanizm jest włączony.
Konfiguracja
| Zmienna | Domyślnie |
|---|---|
NEXT_PUBLIC_IOS_APP_BUNDLE_ID | dev.workers.dtmsoftwares.dmt-cms.twa |
NEXT_PUBLIC_IOS_APP_STORE_COUNTRY | pl |
NEXT_PUBLIC_IOS_APP_STORE_URL | https://apps.apple.com/pl/app/acepark/id6757109661 |
IOS_FORCE_UPDATE_ENABLED | true |
Uwagi wdrożeniowe
- Endpoint leży pod
app/api/public, więc trafia wyłącznie do buildu client (patrz Dwa workery) — aplikacja iOS ładuje domenę klienta, więc to wystarcza. - Ścieżka
/api/public/app-versionjest dopisana dopublicRouteswmiddleware.ts: komunikat musi pokazać się także przed zalogowaniem. - Link do App Store otwiera się poza WKWebView, bo
apps.apple.comnie znajduje się na liścieallowNavigationwcapacitor.config.ts— Capacitor przekazuje taki adres systemowi.