Aller au contenu
WebViewGold Du vibe coding à l'App Store
Français
Obtenir WebViewGold

Claude Code + fiabilité

Écran hors ligne et états d'erreur avec Claude Code : ce que teste l'App Review et comment passer

Un reviewer active le mode avion, touche un peu partout, puis le désactive. Si votre app affiche une page blanche, une erreur brute ou un spinner qui ne s'arrête jamais, c'est un refus pour la guideline 2.1 ou pour fonctionnalité défaillante. WebViewGold couvre les échecs de chargement de page avec un écran hors ligne natif ; tout ce qui se passe dans votre web app en cours d'exécution relève de votre code. Voici comment Claude Code construit cette partie, et comment la tester comme un reviewer.

Dès $109 en paiement unique par plateforme, ou notre équipe s'occupe de tout dès $698.

  • Garantie d'approbation – ou remboursement sous 14 jours
  • Aucun codage requis
  • Paiement unique, mises à jour gratuites
  • Support humain 24/7
  • Conçu en Allemagne depuis 2014 · ISO 27001

Deux couches : la coque native et votre app en cours d'exécution

La coque. Quand la WebView ne parvient pas à charger une page, WebViewGold affiche son écran hors ligne natif au lieu d'une page d'erreur. Sur iOS, vous définissez ses textes avec offlinetitle, offlinemsg, screen1, screen2 et offlinebuttontext, et offlinescreenautoretry réessaie chaque seconde sans qu'il faille toucher l'écran. Sur Android, vous définissez l'arrière-plan avec OFFLINE_SCREEN_BACKGROUND_COLOR ; les textes de l'app se trouvent dans strings.xml. Pour aller plus loin, les deux plateformes peuvent afficher hors connexion une page HTML locale intégrée à l'app (offlinelocalhtmlswitch sur iOS, FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE sur Android), avec un bouton Réessayer qui appelle reconnect:// pour recharger la dernière URL chargée en ligne (API Reconnect).

Votre app. Une single-page app déjà lancée ne déclenche pas de chargement de page quand la connexion tombe. Ses requêtes fetch échouent dans la page, et seul votre code peut afficher quelque chose de sensé : un bandeau hors ligne, un état d'erreur avec Réessayer, un délai d'expiration au lieu d'un spinner sans fin. C'est de là que viennent la plupart des refus liés au hors ligne, et c'est la partie que Claude Code construit ci-dessous. Le hub du mode hors ligne compare les trois niveaux de prise en charge du hors ligne.

Les reviewers appliquent la guideline 2.1 (complétude de l'app : plantages, écrans cassés, contenu provisoire) et Google applique ses règles sur les fonctionnalités défaillantes. Aucun des deux n'attend que votre app fonctionne entièrement hors ligne ; tous deux attendent qu'elle dise ce qui se passe et qu'elle se rétablisse.

Ce que fait Claude Code et ce que vous faites

Claude Code

Écrit le hook de connexion, le wrapper fetch, chaque état de chargement, vide et d'erreur, l'error boundary, la page de repli et des tests Playwright qui simulent le hors ligne et les erreurs serveur, puis les exécute.

Vous

Définissez les textes et les couleurs de l'écran hors ligne natif, copiez la page de repli dans les deux projets WebViewGold, activez le repli si vous le souhaitez, et compilez une fois.

Le test du reviewer

Mode avion au lancement et en cours de session, réseau lent et API en panne, sur de vrais appareils. C'est le seul test qui corresponde à ce que fait l'App Review.

Les cas de panne et qui s'en charge

SituationGéré parCe que l'utilisateur doit voir
Pas de connexion au démarrage de l'appÉcran hors ligne WebViewGold ou repli localVotre message à vos couleurs et Réessayer
La connexion tombe pendant l'utilisationVotre web appUn bandeau hors ligne discret ; actions réseau désactivées ou mises en file d'attente
Réseau très lentVotre web appDes squelettes, puis un délai d'expiration avec Réessayer après 10 à 15 secondes environ
L'API renvoie une erreur 500Votre web appUne phrase simple et Réessayer ; ni stack trace ni JSON
Session expiréeVotre web appRetour à la connexion avec une courte explication, puis retour à la page d'origine
Route inconnueVotre web appUne page introuvable au style d'une app, avec un bouton Accueil
Maintenance planifiéeVotre web appUne page de maintenance que vous pouvez activer sans déploiement

Excellente façon de convertir son app web en app native ! Un délai très court, et un super moyen de mettre ses apps dans les stores sans devoir développer une app native complète !

Kevin Joling · FlightConnections & TrainConnections · Trustpilot

Le prompt Claude Code

Les tests Playwright du point 7 rendent tout cela reproductible : Claude Code les écrit, les exécute via son outil Bash et corrige ce qui échoue.

À coller dans Claude Code
Les reviewers testent notre app en mode avion et sur de mauvais réseaux. L'app tourne dans des apps natives iOS et Android construites avec WebViewGold. Quand le chargement d'une page échoue, le wrapper affiche son écran hors ligne natif, mais une fois notre single-page app lancée, les fetch qui échouent et les changements de route ne sont gérés que par notre code. Rendez chaque échec visible et récupérable.

1. src/lib/use-online.ts : un hook basé sur les événements online et offline de window. Hors ligne, affichez un bandeau discret sous la safe area : Vous êtes hors ligne. Nous rechargerons vos données dès votre retour. Masquez-le une fois la connexion revenue et relancez les requêtes visibles.
2. src/lib/fetch-json.ts : un wrapper fetch unique avec un délai d'expiration de 12 secondes (AbortController), une NetworkError pour le hors ligne, les délais dépassés et les requêtes échouées, et une redirection vers /login?reason=expired en cas de 401, qui ramène au chemin d'origine après la connexion. Remplacez les appels fetch directs par ce wrapper.
3. Chaque écran qui charge des données reçoit un squelette de chargement, un état vide avec une action utile et un état d'erreur avec une phrase simple et un bouton Réessayer. Aucun message d'erreur brut, code de statut ou stack trace dans l'interface.
4. Les actions qui ont besoin du réseau sont désactivées hors ligne et affichent En attente de connexion, ou sont mises en file d'attente et envoyées au retour de la connexion. Ne perdez jamais ce que l'utilisateur a saisi.
5. Une error boundary à la racine avec un écran de repli convivial et un bouton Recharger, une page introuvable au style d'une app avec un bouton Accueil, et une page /maintenance que nous pouvons activer avec une variable d'environnement.
6. Aucun spinner ne doit tourner indéfiniment : chaque état de chargement se termine par du contenu, un état vide ou une erreur.
7. Des tests Playwright qui utilisent context.setOffline(true) pour vérifier le bandeau, l'état d'erreur avec Réessayer et le rétablissement après le retour en ligne, plus un test qui simule une réponse 500 de l'API. Exécutez-les et corrigez les échecs.
8. public/offline-fallback/index.html : une page autonome (CSS inline, sans polices, scripts ni images externes) aux couleurs de notre marque, avec un court message et un bouton Réessayer qui navigue vers reconnect://. Je la copierai dans les projets WebViewGold.

Listez chaque écran modifié et tout ce que vous n'avez pas pu tester.

Le hook de connexion et le wrapper fetch

Assez court pour être relu d'une traite. Notez que navigator.onLine à true ne prouve pas qu'internet fonctionne (pensez au Wi-Fi d'un hôtel) : les requêtes échouées sont donc aussi traitées comme des erreurs réseau.

typescript
// src/lib/use-online.ts
import { useEffect, useState } from "react";

export function useOnline() {
  const [online, setOnline] = useState(typeof navigator === "undefined" ? true : navigator.onLine);
  useEffect(() => {
    const up = () => setOnline(true);
    const down = () => setOnline(false);
    window.addEventListener("online", up);
    window.addEventListener("offline", down);
    return () => {
      window.removeEventListener("online", up);
      window.removeEventListener("offline", down);
    };
  }, []);
  return online;
}

// src/lib/fetch-json.ts
export class NetworkError extends Error {}

export async function fetchJson<T>(url: string, init: RequestInit = {}, timeoutMs = 12000): Promise<T> {
  if (typeof navigator !== "undefined" && !navigator.onLine) throw new NetworkError("offline");
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
  try {
    const res = await fetch(url, { ...init, signal: ctrl.signal });
    if (res.status === 401) {
      window.location.href = "/login?reason=expired&next=" + encodeURIComponent(location.pathname);
      throw new Error("unauthorized");
    }
    if (!res.ok) throw new Error("HTTP " + res.status);
    return (await res.json()) as T;
  } catch (e) {
    if (e instanceof DOMException && e.name === "AbortError") throw new NetworkError("timeout");
    if (e instanceof TypeError) throw new NetworkError("network"); // la requête n'a jamais atteint le serveur
    throw e;
  } finally {
    clearTimeout(timer);
  }
}

Une page de repli intégrée avec reconnect://

Tout est inline, car cette page s'affiche précisément quand rien ne peut être téléchargé. Copiez-la dans le dossier HTML local de chaque projet WebViewGold, comme le décrivent le guide de configuration iOS et le guide de configuration Android (option C).

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <title>Offline</title>
  <style>
    body { margin: 0; min-height: 100vh; display: grid; place-items: center; padding: 24px;
           box-sizing: border-box; text-align: center; background: #0f172a; color: #e2e8f0;
           font-family: -apple-system, system-ui, sans-serif; }
    h1 { font-size: 22px; margin: 0 0 8px; }
    p { margin: 0; line-height: 1.5; color: #94a3b8; }
    button { margin-top: 24px; min-height: 48px; padding: 0 28px; border: 0; border-radius: 12px;
             background: #38bdf8; color: #0f172a; font-size: 17px; font-weight: 600; }
  </style>
</head>
<body>
  <main>
    <h1>You are offline</h1>
    <p>We will take you back to where you were as soon as the connection returns.</p>
    <button type="button" onclick="window.location.href='reconnect://'">Try again</button>
  </main>
</body>
</html>

Configurer le côté natif

Dix minutes par projet, plus un build.

  1. Personnalisez l'écran hors ligne

    iOS : rédigez offlinetitle, offlinemsg, screen1, screen2 et offlinebuttontext avec le ton de votre app et réglez offlinescreenautoretry sur true. Android : définissez OFFLINE_SCREEN_BACKGROUND_COLOR et relisez la formulation hors ligne parmi les textes de l'app dans strings.xml.

  2. Facultatif : le repli intégré

    Copiez la page ci-dessus dans le dossier HTML local et activez offlinelocalhtmlswitch (iOS) ou FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE (Android), en laissant uselocalhtmlfolder / USE_LOCAL_HTML_FOLDER sur false pour que l'URL distante reste la source principale.

  3. Retour visuel du chargement

    Choisissez l'indicateur de chargement natif ou la barre de progression (useLoadingSign, useLoadingProgressBar, loadingIndicatorColor sur iOS ; ACTIVATE_PROGRESS_BAR sur Android). Pour les longues opérations serveur, votre app peut afficher le spinner natif avec spinneron:// et le masquer avec spinneroff://.

  4. Lancez le prompt et déployez

    Relisez le diff, exécutez vous-même les tests Playwright une fois, déployez. La partie web arrive instantanément sur les installations existantes de l'app.

  5. Compilez une fois

    Les textes hors ligne et la page de repli font partie du build natif. Si vous voulez que notre équipe configure tout cela et compile les deux apps, le Full Service s'en charge.

Testez comme un reviewer

  • Démarrage à froid en mode avion : l'écran hors ligne natif (ou votre page de repli) apparaît avec vos textes. Désactivez le mode avion et touchez Réessayer : l'app se charge.
  • Utilisez l'app, puis activez le mode avion : le bandeau apparaît, les boutons réseau affichent En attente de connexion, rien ne devient blanc. Désactivez-le : le bandeau disparaît et les données se rafraîchissent.
  • Simulez un mauvais réseau : sur iPhone, avec le Network Link Conditioner sous Réglages → Développeur (visible une fois l'appareil utilisé avec Xcode) ; sur Android, avec les réglages de vitesse réseau d'un émulateur. Les squelettes apparaissent, puis le contenu ou un délai d'expiration avec Réessayer.
  • Faites pointer un déploiement de preview vers une mauvaise URL d'API : chaque écran affiche son état d'erreur avec Réessayer, aucun n'affiche de JSON brut.
  • Déconnectez-vous dans un autre onglet ou faites expirer la session : l'app revient à la connexion avec une courte explication, puis à la page d'origine.
  • Ouvrez une route qui n'existe pas : une page introuvable au style d'une app, avec Accueil.
  • Mettez l'app en arrière-plan pendant une demi-heure, revenez : elle fonctionne toujours, ou elle se recharge proprement (envisagez autoRefreshEnabled / AUTO_REFRESH_ENABLED si vos données deviennent obsolètes, et vérifiez que cela n'efface pas les formulaires à moitié remplis).

Pièges

  • Des spinners sans fin. Chaque requête a besoin d'un délai d'expiration. Pour un reviewer, un spinner qui ne s'arrête jamais ressemble à un blocage.
  • Une page de repli qui charge des ressources. Les polices web, le CSS d'un CDN ou les images de votre serveur n'existent pas hors ligne. Mettez tout en inline.
  • Bâtir le hors ligne sur un service worker. N'en dépendez pas dans l'app iOS, où WKWebView n'active les service workers que dans des configurations spécifiques. L'écran hors ligne natif et le repli intégré sont les couches fiables.
  • Bloquer le reviewer. Le géoblocage, des règles de pare-feu contre les IP de data centers ou un challenge anti-bot agressif font échouer votre API uniquement pour Apple et Google. Vérifiez vos règles pour les régions depuis lesquelles les reviewers testent.
  • Des écrans provisoires. Les pages « bientôt disponible » et les boutons morts posent aussi problème au regard de la guideline 2.1. Demandez à l'agent de les lister, puisqu'il touche de toute façon à chaque écran.

Questions fréquentes

Mon app doit-elle fonctionner entièrement hors ligne ?

Non. Les reviewers attendent un message clair et un rétablissement qui fonctionne, pas des fonctionnalités hors ligne. Une utilisation entièrement hors ligne exige une version locale intégrée ou une app conçue pour les données hors ligne.

Pourquoi l'écran hors ligne natif n'apparaît-il pas quand je perds la connexion en cours de session ?

Parce que rien n'est en cours de chargement à ce moment-là. Une single-page app en cours d'exécution ne fait échouer que ses propres requêtes fetch : c'est donc à votre code d'afficher le bandeau et les états d'erreur.

Que fait exactement reconnect:// ?

Il recharge la dernière URL chargée avec succès avant que l'app ne bascule sur la page hors ligne. Si la connexion est toujours absente, la page de repli réapparaît.

Claude Code peut-il tester lui-même le mode avion ?

Il peut simuler le hors ligne dans un navigateur avec Playwright (context.setOffline) et simuler des erreurs serveur, ce qui couvre votre code web. L'écran hors ligne natif et le comportement réel du réseau demandent toujours un test sur téléphone.

Où le bandeau hors ligne doit-il apparaître ?

Sous la barre d'état et la safe area, au-dessus du contenu, sans jamais masquer les boutons principaux. Une fine barre en haut est la convention que les utilisateurs reconnaissent.

Trois façons de mettre votre app dans les stores

Même résultat, charge de travail différente de votre côté. Les trois formules incluent la garantie d'approbation et le support humain 24/7.

Faites-le vous-même

$109 par plateforme, paiement unique

La licence WebViewGold : un projet Xcode ou Android Studio prêt à l'emploi. Collez votre URL, définissez le nom et l'icône, activez les fonctionnalités, compilez et soumettez. Mises à jour gratuites à vie.

Voir les offres sur la page principale

Full Service

$698 par plateforme $798

Envoyez-nous votre URL et votre icône. Notre équipe configure, compile et livre votre app sous 72 heures, en marque blanche, projets sources inclus. Les deux plateformes pour $1,158.

Détails du Full Service Propulsé par WeSetupYourWebViewApp

Prix Soldes d'hiver valables jusqu'au 31 décembre 2026.

Prêt à publier votre app ?

Garantie d'approbation App Store & Google Play – ou remboursement sous 14 jours

Vous préférez déléguer ? Full Service : nous configurons, compilons et livrons sous 72 heures, dès $698 par plateforme. Des questions ? Chattez avec nous 24/7.

Les remboursements sont accordés aux conditions indiquées dans notre FAQ : un refus non lié au contenu par Apple et/ou Google, demandé dans les 14 jours suivant l'achat.