Aller au contenu
Sylvain Joffraud l4w
Retour

Wake Lock API : relâché en arrière-plan, à ré-acquérir

Use case courant : une app web où l’utilisateur doit garder un œil sur l’écran pendant plusieurs minutes sans interagir (navigation cartographique, suivi d’un objet/personne en temps réel, monitoring live d’un graphique). On utilise navigator.wakeLock.request('screen') pour empêcher la mise en veille automatique de l’écran.

async function enterTrackingMode() {
  wakeLock = await navigator.wakeLock.request('screen');
  // ... le reste : géoloc, polling, MAJ UI
}

Ça marche : tant que l’onglet est au premier plan, l’écran reste allumé.

Sauf quand l’utilisateur switche d’onglet ou verrouille manuellement, puis revient.

Symptôme

L’utilisateur ouvre l’app, active le mode « garde l’écran allumé », marche un peu, l’écran s’éteint après quelques secondes au lieu de rester allumé. Quand il re-déverrouille / revient à l’onglet, l’écran s’allume normalement mais s’éteint à nouveau dès qu’il arrête de toucher.

Aucune erreur console. La variable wakeLock est toujours définie (l’objet WakeLockSentinel existe encore). On a l’impression que c’est encore actif.

Cause

Le browser relâche automatiquement le wake lock dans plusieurs situations :

C’est documenté mais facile à manquer : le WakeLockSentinel reste un objet JS valide, mais son .released === true. Le browser n’a aucune obligation de réveiller automatiquement le lock quand l’onglet redevient visible. Il faut le re-demander explicitement.

Et même si tu écoutes l’event release sur le sentinel pour mettre à jour ton flag, ça ne suffit pas si tu ne reconnectes pas le visibilitychange au re-acquire.

La bonne approche

Trois choses à câbler ensemble :

let wakeLock = null;

async function acquireWakeLock() {
  if (!('wakeLock' in navigator)) return;          // pas supporté
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => {
      wakeLock = null;                              // (1) flag à jour quand le browser relâche
    });
  } catch (e) {
    console.warn('Wake lock refusé:', e.message);  // (2) NotAllowedError courant (pas de user gesture, etc.)
  }
}

document.addEventListener('visibilitychange', async () => {
  if (modeActif && document.visibilityState === 'visible' && !wakeLock) {
    await acquireWakeLock();                        // (3) ré-acquérir au retour foreground
  }
});

async function exitTrackingMode() {
  if (wakeLock) { try { await wakeLock.release(); } catch {} wakeLock = null; }
}

Les 3 pièces sont nécessaires :

  1. Listener release sur le sentinel pour mettre wakeLock = null quand le browser le relâche tout seul → sans ça, ton check !wakeLock au retour foreground ment
  2. Try/catch : wakeLock.request() peut throw NotAllowedError (pas d’user gesture, page non visible, etc.) — sans catch, ton mode actif crashe silencieusement à la 1re tentative
  3. Re-acquisition au visibilitychange : sans ça, le wake lock relâché en arrière-plan ne revient jamais quand l’utilisateur retourne sur l’onglet

Lessons learned

#web-apis #wake-lock #visibility-api #frontend #mobile #pwa

Questions fréquentes

Pourquoi mon écran s’éteint quand je reviens sur l’onglet alors que mon Wake Lock est toujours actif ?
Le navigateur relâche automatiquement le wake lock quand l’onglet passe en visibilitychange vers hidden (changement d’onglet, verrouillage, passage en arrière-plan). Au retour, il ne le réveille pas tout seul : il faut le ré-acquérir explicitement via un nouveau navigator.wakeLock.request('screen').
Le WakeLockSentinel existe encore mais l’écran s’éteint sans erreur console, comment diagnostiquer ?
L’objet WakeLockSentinel reste une variable JS valide même après relâchement, mais sa propriété .released passe à true. Loggez wakeLock?.released et document.visibilityState dans le handler visibilitychange : si vous voyez released=true au retour en visible sans re-request, c’est l’angle mort.
Comment ré-acquérir correctement un Wake Lock écran après un retour en premier plan ?
Câblez trois pièces ensemble : un listener sur l’event release du sentinel pour remettre le flag à null, un try/catch autour de request() qui peut lever NotAllowedError, et un handler visibilitychange qui rappelle request('screen') quand l’onglet redevient visible et que le mode est actif.
Pourquoi navigator.wakeLock est undefined sur mon site et comment l’éviter ?
L’API Wake Lock n’est disponible que sur secure origin : HTTPS ou localhost. En HTTP simple, navigator.wakeLock est absent. Gardez toujours l’accès avec 'wakeLock' in navigator et prévoyez un fallback gracieux, notamment pour Safari iOS qui ne le supporte que depuis la version 16.4.

Partager cet article :

Article précédent
Leaflet : `marker.remove()` ne nettoie pas son `LayerGroup`
Article suivant
State machine : fail-open vs fail-closed selon la criticité