Aplikacja Expo crashuje na TestFlight: jak to naprawić przed launchem
Praktyczny triage dla aplikacji Expo, które działają lokalnie, a crashują na TestFlight, z regułami decyzji naprawiać czy pisać od nowa.
Aplikacja Expo działała w preview, przeszła symulator, a padła w momencie, w którym TestFlight zrobił się prawdziwy.
TL;DR
Jeśli aplikacja Expo crashuje na TestFlight, potraktuj to jak awarię buildu release, a nie losowy problem Apple. Typowe przyczyny to brakujące zmienne środowiskowe, natywne moduły, które działały w Expo Go, ale nie weszły poprawnie do buildu, niekompatybilne wersje paczek, zepsuta logika startu, zła inicjalizacja logowania albo płatności, albo wyjątek JavaScriptu, który pojawia się tylko w trybie produkcyjnym. Najpierw ściągnij logi z urządzenia, potem odtwórz problem na buildzie preview albo produkcyjnym z EAS, a dopiero potem zdecyduj, czy naprawiasz jeden bloker, czy przepisujesz kruchy fundament. Jeśli crash siedzi blisko logowania, płatności, onboardingu albo wysyłki do App Store, warto wejść w ustrukturyzowany ratunek zamiast w kolejne prompty.
Najważniejsze fakty
Crash na TestFlight oznacza, że aplikacja dotarła do prawdziwego środowiska release na iOS i tam padła.
Sukces w Expo Go nie dowodzi, że natywne moduły, produkcyjne zmienne i logika startu w release są poprawne.
Pierwszym użytecznym artefaktem jest log z urządzenia albo raport crashu, a nie kolejny domysł na podstawie ostatniej zmiany.
Crashe przy starcie zwykle biorą się z logowania, Firebase, Supabase, RevenueCat, deep linków, fontów, splash screena albo brakującej konfiguracji.
Napraw crash, zanim zabierzesz się za screenshoty, teksty do App Store i ASO.
Przepisz fundament, jeśli wersji zależności, natywnych modułów i stanu startowego nie da się czysto wytłumaczyć.
Aplikacje Expo budowane przez AI potrzebują utwardzenia przed TestFlight, zwłaszcza wokół kont, paywalla, analityki i usuwania konta.
Diagnoza: dlaczego build z TestFlight crashuje
Najmocniejsze błędne założenie brzmi: TestFlight zepsuł aplikację. Zwykle nie zepsuł. TestFlight obnażył różnicę między środowiskiem deweloperskim a release.
Expo Go jest hojne. Daje powłokę deweloperską, gotowe natywne moduły, żywe połączenie z Metro i workflow zoptymalizowany pod szybkie iteracje. TestFlight jest odwrotnością. To podpisany build iOS, ze zbundlowanym JavaScriptem, skonfigurowanymi modułami natywnymi, produkcyjną inicjalizacją, zachowaniem trybu release i tymi zmiennymi środowiskowymi, które faktycznie weszły do buildu.
Aplikacja może wyglądać na skończoną w preview, a dalej nie mieć kawałków krytycznych dla launchu:
produkcyjnych kluczy API
produktów i entitlements w RevenueCat
redirect URL-i Supabase
wymaganych config plugins
wersji paczek kompatybilnych z release
obsługi błędów przy starcie
Najczęstszy objaw jest brutalny: aplikacja się otwiera, błyska splash screenem i się zamyka. Czasem wisi na pustym ekranie. Czasem logowanie albo inicjalizacja zakupów zabija aplikację, zanim wyrenderuje się pierwszy ekran.
To nie jest bug UI. To bug gotowości produkcyjnej.
Przy buildach wspieranych przez AI wzorzec jest ostrzejszy. Cursor, Bolt, Replit, Rork i podobne narzędzia szybko generują działające ekrany, ale optymalizują pod następny widoczny błąd. Paczka wchodzi bez sprawdzenia zachowania w release na iOS, Expo dostaje downgrade, żeby uciszyć ostrzeżenie, a kod logowania jest kopiowany po kolejnych ekranach, aż preview zadziała.
Efekt to kod, który potrafi zrobić demo, ale nie przeżyje TestFlight.
Ścieżka naprawy: wyizoluj awarię widoczną tylko w release
Zacznij od logów. Nie zaczynaj od przepisywania ekranu, który akurat pojawił się przed crashem.
Zainstaluj build z TestFlight na fizycznym urządzeniu.
Odtwórz crash od świeżej instalacji.
Ściągnij log z urządzenia z Xcode Organizer, macOS Console albo Twojego zwykłego setupu do debugowania iOS.
Znajdź pierwszy prawdziwy wyjątek, a nie ostatni komunikat z kaskady.
Napraw jedną przyczynę, zbuduj ponownie i przetestuj od czystej instalacji.
Pierwszy wyjątek ma znaczenie, bo późniejsze komunikaty opisują skutki. Na przykład "main has not been registered" pojawia się często po tym, jak wcześniejszy moduł padł przy starcie. Użyteczne pytanie brzmi: który import, która wartość konfiguracji albo który natywny moduł padł, zanim React Native zdążył coś wyrenderować.
Sprawdź najpierw te obszary.
1. Zmienne środowiskowe i konfiguracja produkcyjna
Lokalny development w Expo potrafi ukryć brakującą konfigurację. TestFlight nie potrafi.
Zweryfikuj każdą produkcyjną wartość: bazowy adres API, klucze Supabase, konfigurację Firebase, klucz SDK RevenueCat, endpoint bramki AI, schematy redirect, bundle ID, deep linki i zmienne z profilu buildu EAS.
Jeśli klucz istnieje lokalnie, ale nie ma go w EAS, aplikacja może paść, zanim pokaże cokolwiek sensownego. Kod startowy powinien podczas testów wewnętrznych zawodzić kontrolowanie, z widocznym ekranem błędu, a nie zabijać całą aplikację.
2. Natywne moduły, które Expo Go zamaskowało
Expo Go nie dowodzi, że każda natywna zależność jest obecna w Twoim samodzielnym buildzie. Jeśli dodałeś kamerę, notyfikacje, RevenueCat, obsługę gestów, mapy, zakupy w aplikacji, dostęp do plików albo SDK logowania, sprawdź, czy zależność jest zainstalowana w wersji kompatybilnej z Expo i czy robota z config plugin została wykonana.
Odpal standardowe kontrole zdrowia Expo, potem obejrzyj ostatnio dodane paczki. Jeśli crash pojawił się po zmianie zależności, zakładaj winę warstwy natywnej, dopóki nie udowodnisz czegoś innego.
3. Kod startowy, który robi za dużo
Buildy release karzą kruchy kod startowy.
Złe wzorce startu:
inicjalizacja płatności, zanim znany jest stan logowania
wywołanie API przy imporcie modułu
czytanie secure storage, zanim aplikacja jest gotowa
założenie, że obiekt użytkownika istnieje
routing przed zakończeniem przywracania sesji
rzucanie błędów wewnątrz providerów
Powłoka aplikacji ma być nudna. Wczytuje konfigurację, przywraca sesję, decyduje o pierwszym ekranie i pokazuje kontrolowany stan, jeśli coś padnie.
4. Logika logowania i płatności
Crashe blisko logowania, zakładania konta, restore purchases albo ładowania paywalla są wysokiego ryzyka, bo te przepływy sterują przychodem i gotowością na review.
Logowanie musi odpowiadać, czy użytkownik jest zalogowany, czy sesja jest ważna, czy onboarding jest skończony i co się dzieje po wylogowaniu albo usunięciu konta.
Płatności muszą odpowiadać, czy produkty da się pobrać, czy restore purchases działa, czy sprawdzanie entitlements realnie kontroluje dostęp i czy produkty sandbox i produkcyjne są poprawnie zmapowane.
Jeśli te odpowiedzi są rozsypane po ekranach, nie łataj na ślepo. Potrzebujesz audytu kodu, bo crash jest prawdopodobnie objawem splątanego stanu.
5. Praca pod App Store, która dotyka runtime
Część roboty przed wysyłką zmienia binarium, nie tylko listing. Privacy manifest, uprawnienia, dostawcy logowania, universal links, push notyfikacje i konfiguracja subskrypcji potrafią zmienić zachowanie w release. Napraw crash przed polerowaniem sklepu. Screenshoty nie mają znaczenia, jeśli recenzent nie może otworzyć aplikacji.
Zdecyduj: naprawa czy przepisanie
Reguła: naprawiaj istniejącą aplikację, jeśli awaria jest odizolowana, a ścieżka do launchu zrozumiała. Przepisz fundament, jeśli każda odpowiedź wymaga archeologii.
Naprawiaj, gdy:
crash ma jeden jasny wyjątek
wersje Expo SDK i React Native są spójne
natywne moduły są znane i potrzebne
stan logowania ma jedno źródło prawdy
logika płatności jest scentralizowana
developer potrafi opisać przepływ startu
Przepisz krytyczną ścieżkę, gdy:
Expo zostało zdowngradowane albo wymuszone pod jedną paczkę
instalacje paczek wymagają flag force
to samo sprawdzenie logowania albo entitlement występuje w wielu miejscach
buildy release padają po każdej poprawce z innego powodu
nie ma jasnego właściciela onboardingu, logowania, dostępu płatnego i stanu nawigacji
wymagania App Store nigdy nie były brane pod uwagę przy projektowaniu przepływów
Przepisanie nie oznacza wyrzucenia produktu. Zachowaj zwalidowany pomysł, teksty, ekrany, markę i działający przepływ AI, jeśli są sensowne. Wymień fundament, który blokuje launch.
Ratunek dla aplikacji w Silpho istnieje dokładnie na ten moment decyzji: zaudytować aplikację Expo albo React Native, wskazać prawdziwe blokery i zdecydować, czy naprawiać, przepisać, czy wejść w sprint launchowy.
Porównanie
| Ścieżka | Koszt | Dla kogo | Ryzyko |
|---|---|---|---|
| Triage logów własnymi siłami | 0 zł plus Twój czas | Techniczni founderzy z czystą aplikacją Expo i jednym jasnym crashem | Wolno, jeśli pierwszy błąd jest tylko objawem |
| Kickstart | 1 990 zł netto | Osoby, które potrzebują boilerplate, sesji 1 na 1, code review i wsparcia | Ma sens, gdy implementację dalej robisz sam |
| Audyt Ratunek dla aplikacji | 1 990 zł netto | Aplikacje z AI, gdzie decyzja naprawa kontra przepisanie jest niejasna | Audyt może pokazać, że kodu nie warto zachowywać |
| Sprint launchowy | 15 900 zł netto z iOS i Androidem | Founderzy, którzy potrzebują 4 tygodni pracy zrobionej od A do Z | Zakres musi zmieścić się w sprincie |
| Launch + Growth | 23 900 zł netto z iOS i Androidem | Aplikacje gotowe na przychód, które potrzebują też materiałów i ASO | Przesada przy jednym odizolowanym crashu |
FAQ
Dlaczego moja aplikacja Expo działa lokalnie, a crashuje na TestFlight?
Lokalny development i TestFlight to inne środowiska. TestFlight używa podpisanego buildu release, zbundlowanego JavaScriptu, produkcyjnej konfiguracji i prawdziwego zachowania modułów natywnych. Brakujący klucz, niekompatybilna zależność albo wyjątek przy starcie bywają niewidoczne lokalnie i śmiertelne w release.
Czy aplikacja Expo wygenerowana przez AI przejdzie TestFlight?
Tak, jeśli utwardzisz ją jak produkcyjną. Ryzyko nie leży w tym, że pomagało AI. Ryzyko to brakujące warstwy produkcyjne: stan logowania, płatności, sprawdzanie entitlements, crash reporting, analityka, prywatność, usuwanie konta i testowanie buildu release.
Kiedy przestać łatać crash?
Gdy każda poprawka rodzi nową awarię albo gdy nikt nie potrafi opisać przepływu startu. To zwykle znaczy, że crash nie jest odizolowany. Wtedy robisz ustrukturyzowany audyt i decydujesz o przepisaniu krytycznej ścieżki.
Co naprawić przed ponownym wysłaniem na TestFlight?
Napraw źródłowy crash, potem przetestuj od świeżej instalacji na urządzeniu. Później sprawdź rejestrację, logowanie, wylogowanie, usuwanie konta, ładowanie paywalla, restore purchases, odmowę uprawnień, wolną sieć i główny przepływ AI, jeśli go masz.
Czy wysyłka do App Store wymaga czegoś więcej niż naprawienia crashu?
Tak. Niecrashujący build to dopiero podłoga. Dalej potrzebujesz odpowiedzi o prywatność, usuwania konta, jeśli są konta, informacji o subskrypcji, jeśli sprzedajesz subskrypcje, materiałów do sklepu, linków wsparcia, metadanych i notatek dla recenzenta.
Czy Silpho może naprawić sam crash, bez przepisywania aplikacji?
Czasem tak. Jeśli kod da się uratować, ścieżka ratunkowa ustabilizuje blokery launchu. Jeśli fundament Expo, logowanie, płatności i nawigacja są splątane, przepisanie krytycznej ścieżki jest zwykle krótszą drogą do sklepu.
