Offline-Modus und Fehlerzustände, die das App-Review überstehen: ein Codex-Workflow für WebViewGold-Apps
Manche Reviewer schalten den Flugmodus ein, und jeder Reviewer trifft irgendwann auf einen langsamen Request. Eine gewrappte Web-App hat zwei Offline-Ebenen: WebViewGold fängt den Moment ab, in dem die Seite überhaupt nicht laden kann, und deine Web-App muss jeden Request abfangen, der nach dem Laden scheitert. Für die zweite Ebene passt Codex gut, denn es kann jeden Datenaufruf in der Codebasis auflisten und jeden Fehlerzustand mit Tests belegen, die das Netzwerk kappen.
Ab $109 einmalig pro Plattform, oder unser Team erledigt alles ab $698.
Genehmigungsgarantie – oder Geld zurück innerhalb von 14 Tagen
Kein Programmieren nötig
Einmalzahlung, kostenlose Updates
24/7 Support von echten Menschen
Made in Germany seit 2014 · ISO 27001
9:41
Deine App
Deine AppJetzt auf dem Smartphone
App Store · Google Play Freigegeben
Ziel und Blick des Reviewers
Bei Richtlinie 2.1 (App Completeness) landen Offline-Probleme: ein Spinner, der nie aufhört, ein weißer Screen nach einem gescheiterten Request, ein rohes "TypeError: Failed to fetch" auf einer Karte, ein Formular, das alles verliert, was du eingetippt hast (die 2.1-Ablehnung erklärt). Google Play verbucht dasselbe unter fehlerhafter Funktionalität. Nichts davon braucht den Flugmodus: Ein kostenloser Hosting-Tarif, der nach Inaktivität einschläft, eine kalte Serverless-Funktion oder ein schwaches Hotel-WLAN schaffen das auch.
Das Ziel: Die App zeigt nie einen leeren oder eingefrorenen Screen. Beim Start ohne Netzwerk erscheint ein nativer Offline-Bildschirm mit einem Button zum erneuten Versuchen. Mitten in der Session zeigt jeder Screen einen Ladezustand, der endet, einen Fehlerzustand mit einem Button zum erneuten Versuchen oder Daten aus dem Cache mit dem Hinweis, dass sie veraltet sein können.
Zwei Ebenen, die du brauchst, zwei, die du ergänzen kannst
Nativer Offline-Bildschirm (WebViewGold)
Erscheint, wenn die App deine URL nicht laden kann. Auf iOS kommen die Texte für Dialog und Bildschirm aus offlinetitle, offlinemsg, screen1, screen2 und offlinebuttontext, und offlinescreenautoretry versucht es jede Sekunde erneut, ohne dass jemand tippen muss. Auf Android passt OFFLINE_SCREEN_BACKGROUND_COLOR ihn an deine Marke an. Kein Web-Code beteiligt.
Fehlerzustände in der Web-App (Codex)
Jeder Request bekommt ein Timeout, einen Fehlerzustand mit erneutem Versuch und eine verständliche Meldung. Auf diese Ebene stoßen Reviewer am häufigsten, und genau sie automatisiert dieser Guide.
Mitgelieferte Fallback-Seite (optional)
Mit offlinelocalhtmlswitch (iOS) oder FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE (Android) zeigt die App offline eine Seite aus dem local-html-Ordner des Projekts, und ein Button, der zu reconnect:// navigiert, lädt die letzte Online-URL neu (Reconnect-API). Auf iOS können zipfiledownloadfromserver und zipfileremoteurl diesen Fallback von deinem Server aktualisieren.
Daten aus dem Cache (optional, Firebase)
Der persistente lokale Cache von Firestore liefert offline die zuletzt bekannten Dokumente aus. Listen werden also weiter gerendert, mit einem Hinweis "zuletzt aktualisiert", und Schreibvorgänge warten in einer Warteschlange, bis die Verbindung zurück ist.
Der Vertrag für Fehlerzustände in der AGENTS.md
Schreib die Regeln einmal als Invarianten in die AGENTS.md der Web-App. Jede spätere Aufgabe ("füge eine Berichtsseite hinzu") bekommt die Fehlerzustände dann gratis mit, und der Abschnitt Review guidelines lässt das Codex Code Review Rückschritte in Pull Requests erkennen.
markdown
## Network and error states (every screen)
- All HTTP calls go through src/lib/request.ts: request(path, { timeoutMs = 10000 }).
It uses AbortSignal.timeout, retries idempotent GETs once with backoff, and throws
typed errors (OfflineError, TimeoutError, HttpError with status) that carry a
user-facing message. Components never call fetch directly.
- Every data view renders exactly one of: loading (skeleton, ends after 10 s at the
latest), content, empty (helpful text and a next action), error (message and a
"Try again" button).
- No raw error text in the UI: no "TypeError", no stack traces, no JSON.
- Offline banner: listen to the online and offline events and render
<div role="status">You are offline. Changes will sync when you are back.</div>
Do not rely on navigator.onLine alone; a failed request also counts as offline.
- Forms keep their input when a submit fails. Submit buttons show progress and
re-enable on error. Never send the same mutation twice without an idempotency key.
- Firestore: initializeFirestore with persistentLocalCache. Show "Last updated"
when snapshot.metadata.fromCache is true.
- Express: error middleware returns JSON { error, message } with the right status,
never an HTML error page. GET /healthz answers 200 without touching the database.
- No service worker for offline inside the native app. WebViewGold's offline screen
and the bundled fallback page handle "no network at launch".
## Review guidelines
- P1: fetch() or axios outside src/lib/request.ts, or any request without a timeout.
- P1: a catch block that swallows an error without showing an error state.
- P1: a loading state with no exit (no timeout, no error branch).
Mit einer gut optimierten Version Ihrer Web-App können Sie innerhalb von wenigen Minuten eine beeindruckende mobile App erstellen. Zusätzlich dazu ist der Kundenservice sehr nett und hilfsbereit! Ich kann WebViewGold nur empfehlen :-)
Julian Koch · Mitbegründer von DuelDonkey · CodeCanyon
Bestandsaufnahme und Fix: die Codex-Aufgabe
Diese Aufgabe funktioniert gut als Cloud-Aufgabe, denn das Ergebnis ist ein großes, aber mechanisches Diff, das du als Pull Request lesen willst. Ergänze in der Cloud-Umgebung npx playwright install --with-deps chromium im Setup-Skript, damit der Browser bereitsteht, bevor der Agent startet; in der CLI bittet Codex um Freigabe, wenn es zur Installation das Netzwerk braucht. Die UI-Texte im Prompt ("Try again", "You are offline") passen zu den Tests weiter unten; ist deine App auf Deutsch, passe Texte und Tests gemeinsam an.
In Codex einfügen (Cloud-Aufgabe, CLI oder IDE-Erweiterung)
Lies AGENTS.md, besonders "Network and error states". Diese Web-App läuft in nativen iOS- und Android-Apps, die mit WebViewGold gebaut sind, und das App-Review testet sie in schlechten Netzen.
1. Bestandsaufnahme: Finde jeden Netzwerkaufruf (fetch, axios, Firestore getDoc, getDocs und onSnapshot, Server-Sent Events oder WebSockets, Datei-Uploads). Schreibe docs/network-inventory.md mit einer Zeile pro Aufruf: Datei, Screen, Aufruf, aktuelle Behandlung von Laden, Leerzustand und Fehler.
2. Lege src/lib/request.ts wie in AGENTS.md beschrieben an und verlagere jeden HTTP-Aufruf dorthin.
3. Implementiere für jeden Screen aus der Bestandsaufnahme die vier Zustände: Laden, das spätestens nach 10 Sekunden endet, Inhalt, leer und Fehler mit "Try again". Verwende eine einzige ErrorState- und eine einzige EmptyState-Komponente.
4. Füge das Offline-Banner mit role="status" hinzu, gesteuert über die Events online und offline und über OfflineError aus request().
5. Formulare: Eingaben bei einem Fehler behalten, den Fehler neben dem Absenden-Button zeigen, den Button wieder aktivieren.
6. Firestore: Stelle auf persistentLocalCache um und zeige "Last updated", wenn snapshot.metadata.fromCache true ist.
7. Express: eine JSON-Fehler-Middleware, ein JSON-404-Handler für /api und GET /healthz.
8. Lege native-fallback/index.html an: eine eigenständige Datei (Inline-CSS, das Logo als Inline-SVG oder Data-URI, keine externen Requests) mit dem App-Namen, dem Text "You are offline" und einem Button "Try again", der zu reconnect:// navigiert. Ich kopiere sie in den local-html-Ordner der nativen Projekte.
9. Playwright-Tests: abgebrochene API-Requests, API-Requests, die nie antworten, und ein Browser-Kontext, der offline und wieder online geschaltet wird. Jeder Fall muss innerhalb von 12 Sekunden in einem Fehler- oder Offline-Zustand enden und darf keinen rohen Fehlertext zeigen. Installiere Playwright, falls es fehlt (frag vorher).
Schließe mit der Bestandsaufnahme, der Liste der geänderten Screens und allem, was du nicht abdecken konntest.
Die Tests, die es beweisen
Drei Netzwerkausfälle decken das meiste ab, worauf ein Reviewer stoßen kann. Sie laufen in der Codex-Sandbox und in der CI, denn sie brauchen nur den lokalen Dev-Server.
javascript
// tests/offline.spec.js (Playwright)
import { test, expect } from "@playwright/test";
test("failed API shows a retry, not a white screen", async ({ page }) => {
await page.route("**/api/**", (route) => route.abort("internetdisconnected"));
await page.goto("/dashboard");
await expect(page.getByRole("button", { name: /try again/i })).toBeVisible({ timeout: 12000 });
await expect(page.getByText(/TypeError|Failed to fetch/)).toHaveCount(0);
});
test("hanging API never leaves an endless spinner", async ({ page }) => {
await page.route("**/api/**", () => { /* never answer: a server that hangs */ });
await page.goto("/dashboard");
await expect(page.getByRole("button", { name: /try again/i })).toBeVisible({ timeout: 12000 });
});
test("offline banner appears and clears", async ({ page, context }) => {
await page.goto("/dashboard");
await context.setOffline(true);
await expect(page.getByRole("status")).toContainText(/offline/i);
await context.setOffline(false);
await expect(page.getByRole("status")).toHaveCount(0);
});
Die Offline-Einstellungen von WebViewGold auf einen Blick
Ziel
iOS (Config.swift)
Android (Config.java)
Offline-Texte und Button-Beschriftung
offlinetitle, offlinemsg, screen1, screen2, offlinebuttontext (übersetzbar über alternatelanguage1 und alternatelanguage2)
Keine Text-Keys in Config.java dokumentiert; Hintergrundfarbe über OFFLINE_SCREEN_BACKGROUND_COLOR
Erneuter Versuch ohne Tippen
offlinescreenautoretry
Keine dokumentierte Option; nutze eine Fallback-Seite mit reconnect://
Mitgelieferte Fallback-Seite
offlinelocalhtmlswitch true, Seite im local-html-Ordner
FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE true, Seite im local-html-Ordner
Erneut versuchen aus dem Fallback
reconnect://
reconnect://
Den Fallback aus der Ferne aktualisieren
zipfiledownloadfromserver und zipfileremoteurl
Mit dem Build ausliefern
Aktualisieren, wenn die App aus dem Hintergrund zurückkommt
autoRefreshEnabled
AUTO_REFRESH_ENABLED
Ausliefern
Den Vertrag in die AGENTS.md schreiben
Füge den Abschnitt oben ein und passe Pfade und Timeouts an dein Projekt an. Committe ihn, bevor die Aufgabe läuft, damit eine Cloud-Aufgabe ihn sieht.
Die Aufgabe für Bestandsaufnahme und Fix ausführen
Als Cloud-Aufgabe bekommst du ein Diff und einen Pull Request; in der CLI nutzt du codex --sandbox workspace-write --ask-for-approval on-request. So oder so müssen die Playwright-Tests grün sein.
Gegen die Bestandsaufnahme prüfen
Jede Zeile in docs/network-inventory.md sollte zu einem Screen mit vier Zuständen passen. Kommentiere @codex review im Pull Request, um die Review-Richtlinien ein zweites Mal anzuwenden.
Die native Ebene konfigurieren
Schreib die Offline-Texte im Ton und in der Sprache deiner App, entscheide dich für oder gegen offlinescreenautoretry, setze die Hintergrundfarbe für Android, und wenn du die Fallback-Seite willst, kopiere native-fallback/index.html nach local-html/index.html und schalte offlinelocalhtmlswitch oder FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE ein (Android-Docs zu Reconnect).
Das Netzwerk absichtlich kaputtmachen
Flugmodus beim Start und mitten in der Session, auf echten Geräten. Auf dem iPhone simuliert der Network Link Conditioner in den Entwicklereinstellungen (verfügbar, nachdem das Gerät mit Xcode verbunden war) sehr schlechte Netze und Totalausfall; auf Android nutzt du den Flugmodus oder die Netzwerkeinstellungen des Emulators.
Den Reviewer informieren
Wenn die App eine Internetverbindung braucht, schreib das in die Review-Notizen, zusammen mit dem, was die App offline zeigt. Für den Rest der Einreichung siehe den Codex-Release-Workflow.
Flugmodus-Skript (arbeite es ab, bevor der Reviewer es tut)
Kaltstart im Flugmodus: Der native Offline-Bildschirm erscheint, im Look deiner Marke und gut lesbar, und der Button zum erneuten Versuchen funktioniert, sobald das Netz zurück ist.
Flugmodus mitten in der Session: Das Offline-Banner erscheint, der aktuelle Screen behält seinen Inhalt, und Aktionen zeigen eine klare Meldung.
Wieder online: Das Banner verschwindet, der Retry-Button lädt neu, und nichts wurde doppelt abgeschickt.
Ein hängender Server (stoppe deine API oder nutze ein Profil mit 100 Prozent Paketverlust im Network Link Conditioner): Jeder Spinner endet nach etwa zehn Sekunden.
Fallback-Seite, falls aktiviert: Sie lädt ohne Netzwerk, hat keine kaputten Bilder oder Schriften, und reconnect:// führt zur letzten Seite zurück.
Die App eine Weile im Hintergrund lassen und zurückkehren: Mit autoRefreshEnabled oder AUTO_REFRESH_ENABLED wird die Seite aktualisiert; ohne verhalten sich veraltete Screens trotzdem korrekt.
Die eingeloggte Session übersteht einen Offline-Start; niemand wird durch einen Netzwerkfehler ausgeloggt.
Stolperfallen
Auf navigator.onLine vertrauen. Es bleibt hinter einem Captive Portal im WLAN oder bei einer toten Verbindung true; behandle gescheiterte und abgelaufene Requests ebenfalls als offline.
Eine Fallback-Seite, die Webfonts, ein CDN-Skript oder ein entferntes Logo lädt. Offline scheitern diese Requests, und die Seite sieht kaputt aus. Bette alles inline ein.
Retry-Stürme: Buttons, die pro Tippen mehrere Requests abfeuern, oder automatische Wiederholungen ohne Backoff, die auf eine ohnehin angeschlagene API einhämmern.
Express oder ein Proxy antwortet mit einer HTML-Fehlerseite, die der Client als JSON zu parsen versucht ("Unexpected token <"). Die JSON-Fehler-Middleware behebt das an der Quelle.
Den Offline-Plan auf einem Service Worker aufbauen. Auf iOS führt WKWebView Service Worker in der Regel nur für Apps aus, die mit App-Bound Domains konfiguriert sind; betrachte einen Service Worker also als Bonus für Browser-Nutzer.
Ein kostenloser Hosting-Tarif, der einschläft: Der erste Request nach einer ruhigen Phase dauert so lange, dass es wie ein Hänger aussieht. Halte die API warm oder wechsle vor der Einreichung den Tarif.
Häufig gestellte Fragen
Muss meine App komplett offline funktionieren, um das Review zu bestehen?
Nein. Apps, die einen Server brauchen, dürfen eine Verbindung voraussetzen, solange sie mit deren Fehlen sauber umgehen: ein klarer Offline-Bildschirm, Fehlerzustände mit erneutem Versuch, keine eingefrorenen oder leeren Screens. Erwähne in den Review-Notizen, dass die App eine Internetverbindung braucht.
Was ist der Unterschied zwischen dem Offline-Bildschirm und der Fallback-Seite?
Der Offline-Bildschirm ist nativ und wird mit ein paar Texten und Optionen konfiguriert. Die Fallback-Seite ist dein eigenes HTML im local-html-Ordner des Projekts. Sie wird stattdessen angezeigt, wenn offlinelocalhtmlswitch (iOS) oder FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE (Android) eingeschaltet ist, und kann einen reconnect://-Button anbieten.
Kann Codex das Offline-Verhalten testen?
Ja, für die Web-Ebene. Playwright kann Requests abbrechen, sie hängen lassen und den Browser-Kontext offline schalten, alles in der Codex-Sandbox. Der native Offline-Bildschirm und die Fallback-Seite brauchen trotzdem einen Gerätetest im Flugmodus.
Soll ich die Offline-Persistenz von Firestore aktivieren?
Bei Apps, in denen vor allem gelesen wird, ja: Listen werden aus dem Cache gerendert, und Schreibvorgänge werden später synchronisiert. Zeig an, wann Daten aus dem Cache kommen, und denk an geteilte Geräte, bevor du sensible Daten cachst.
Wird AbortSignal.timeout in der App unterstützt?
Ja, in aktuellen System-WebViews; Safari unterstützt es ab Version 16. Wenn du ältere iOS-Versionen unterstützt, bitte Codex um einen AbortController mit setTimeout als Fallback in request.ts.
Drei Wege, deine App in die Stores zu bringen
Gleiches Ergebnis, unterschiedlich viel Arbeit auf deiner Seite. Alle drei kommen mit Genehmigungsgarantie und 24/7 Support von echten Menschen.
Selbst machen
$109 pro Plattform, einmalig
Die WebViewGold-Lizenz: ein fertiges Xcode- oder Android-Studio-Projekt. URL einfügen, Name und Icon setzen, Features einschalten, bauen und einreichen. Kostenlose Updates für immer.
Kein Mac, kein Xcode, kein Android Studio: Du konfigurierst im Browser, wir bauen beide Apps in der Cloud und übergeben sie an App Store Connect und die Play Console.
Schick uns deine URL und dein Icon. Unser Team konfiguriert, baut und liefert deine App innerhalb von 72 Stunden, White-Label, inklusive Quellprojekten. Beide Plattformen für $1,158.
Erstattungen erfolgen zu den in unseren FAQ genannten Bedingungen: eine nicht inhaltsbedingte Ablehnung durch Apple und/oder Google, geltend gemacht innerhalb von 14 Tagen nach dem Kauf.