Skip to content

Démarrage de l'app ​

Que se passe-t-il entre le moment où l'on touche l'icône et le moment où l'écran de pointage s'affiche ?

Étape 1 : package.json ​

json
{
  "main": "expo-router/entry"
}

La clé main dit quel fichier lancer en premier. Ici ce n'est pas un fichier de l'app, mais expo-router lui-même. Il n'y a donc pas de App.tsx : expo-router va lire le dossier src/app/ et construire la navigation tout seul.

Étape 2 : app.json ​

Ce fichier configure l'application native :

CléValeurEffet
nameTimeManagerLe nom sous l'icône
schemetimemanagermobileLes liens timemanagermobile://... ouvrent l'app
orientationportraitPas de rotation
userInterfaceStylelightToujours en clair (la maquette n'a pas de mode sombre)
iconassets/images/icon.pngL'icône iOS et par défaut
android.adaptiveIcontrois images + fond blancL'icône Android qui s'adapte au thème du téléphone
pluginsexpo-router, expo-splash-screen, expo-localization, expo-secure-store, expo-sharingConfiguration native de chaque module
experiments.typedRoutestruerouter.push('/xxx') est vérifié par TypeScript
experiments.reactCompilertrueReact optimise automatiquement les rendus

Le splash (écran de lancement) a un fond #f5f5f4 et le logo de 120 px au centre.

Étape 3 : src/app/_layout.tsx ​

C'est le premier fichier de notre code qui s'exécute. Il enveloppe toute l'application.

3.1 Les langues d'abord ​

tsx
import '@/i18n';

Cette ligne est la toute première. Elle configure i18next avec la langue du téléphone, pour que n'importe quel texte affiché ensuite soit déjà traduit.

3.2 Garder le splash ​

tsx
SplashScreen.preventAutoHideAsync();

Sans ça, le splash disparaîtrait tout de suite et on verrait un écran blanc pendant le chargement.

3.3 Les providers ​

tsx
export default function RootLayout() {
  return (
    <SafeAreaProvider>
      <OnboardingProvider>
        <SessionProvider>
          <DirectoryProvider>
            <ToastProvider>
              <RootStack />
            </ToastProvider>
          </DirectoryProvider>
        </SessionProvider>
      </OnboardingProvider>
    </SafeAreaProvider>
  );
}

L'ordre n'est pas au hasard : un provider peut utiliser ceux qui l'entourent. DirectoryProvider a besoin de savoir qui est connecté pour décider quoi charger, il est donc dans SessionProvider.

Dès leur création :

  • OnboardingProvider lit dans SecureStore si la présentation a été vue ;
  • SessionProvider lit le jeton CSRF enregistré et, s'il existe, demande /auth/me pour retrouver l'utilisateur ;
  • DirectoryProvider attend qu'il y ait un utilisateur, puis charge les utilisateurs et les équipes si c'est un manager ou le GM.

3.4 Attendre que tout soit prêt ​

tsx
function RootStack() {
  const { ready, user } = useSession();
  const onboarding = useOnboarding();
  const [fontsLoaded, fontError] = useFonts(fontAssets);
  const loaded = ready && onboarding.ready && (fontsLoaded || fontError);

  useEffect(() => {
    if (loaded) SplashScreen.hideAsync();
  }, [loaded]);

  if (!loaded) return null;
  // ...
}

Trois choses doivent être prêtes : la session (on sait si quelqu'un est connecté), la présentation (on sait si elle a été vue) et les polices. Tant que ce n'est pas le cas, RootStack n'affiche rien et le splash reste. Dès que tout est prêt, le splash disparaît.

Si les polices n'arrivent pas à se charger (fontError), l'app démarre quand même avec la police du système.

3.5 Choisir les écrans autorisés ​

tsx
<Stack>
  <Stack.Protected guard={!!user}>
    <Stack.Screen name="(tabs)" />
  </Stack.Protected>
  <Stack.Protected guard={!user && onboarding.seen}>
    <Stack.Screen name="sign-in" />
    <Stack.Screen name="forgot-password" />
  </Stack.Protected>
  <Stack.Protected guard={!!user || !onboarding.seen}>
    <Stack.Screen name="onboarding" />
  </Stack.Protected>
  <Stack.Screen name="reset-password" />
  <Stack.Screen name="set-password" />
  <Stack.Screen name="account-deleted" />
  <Stack.Screen name="confirm-email" />
</Stack>

Un Stack.Protected rend ses écrans inaccessibles quand sa condition (guard) est fausse. expo-router ouvre alors le premier écran autorisé.

SituationÉcrans autorisésCe qu'on voit
Premier lancement, personne de connectéonboarding, écrans publicsLa présentation
Présentation vue, personne de connectésign-in, forgot-password, écrans publicsLa connexion
Connecté(tabs), onboarding, écrans publicsL'onglet Clock

Les quatre derniers écrans sont toujours accessibles : on y arrive par un lien reçu par mail, connecté ou non.

Pas de redirection à la main

Quand la connexion réussit, user passe de null à un objet. La condition !!user devient vraie, celle de sign-in devient fausse, et expo-router bascule tout seul vers les onglets. Pareil à la déconnexion. Aucun écran ne fait router.replace('/sign-in') après un login ou un logout.

Étape 4 : src/app/(tabs)/_layout.tsx ​

Une fois connecté, on entre dans le groupe (tabs). Son layout crée la barre d'onglets et déclare les 24 écrans internes. Voir Navigation.

Résumé ​