1 2 <!doctype html>3 <html lang="es">4 <head>5 <meta charset="utf-8">6 <meta name="viewport" content="width=device-width, initial-scale=1">7 <meta name="theme-color" content="#172b4d">8 <title>Prueba GPS con pantalla bloqueada</title>9 <style>10 :root {color-scheme:dark; font-family: system-ui, -apple-system, sans-serif}11 body {margin:0; background:#101826; color:#eaf1fb; padding:20px;}12 main {max-width:720px; margin:0 auto}13 h1 {font-size:1.55rem;margin:0 0 6px}14 p {color:#bac7db;line-height:1.5}15 .panel {background:#18243a; border:1px solid #34435a; border-radius:14px; padding:14px; margin:12px 0}16 .buttons {display:flex;flex-wrap:wrap; gap:9px}17 button {background:#479cff; color:#071524; border:0; border-radius:10px; padding:13px 16px; font-weight:700; font-size:1rem}18 button:disabled {opacity:.45}19 button.secondary {background:#34435a; color:#eaf1fb}20 .stats {display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px}21 .value {font-weight:750;font-size:1.35rem;overflow-wrap:anywhere}22 .name {font-size:.82rem; color:#a6bbd4}23 pre {font:12px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; background:#0d1420; padding:12px; border-radius:8px; max-height:360px;overflow-y:auto}24 .ok {color:#91f0bd}.bad {color:#ffb4b4}25 </style>26 </head>27 <body>28 <main>29 <h1>🛰️ Prueba GPS en segundo plano</h1>30 <p>Inicia la prueba, concede permiso de ubicación, espera a recibir coordenadas y <strong>bloquea la pantalla mientras caminas</strong>. Al desbloquear, mira si se han registrado posiciones durante el bloqueo.</p>31 <div class="panel">32 <div class="buttons">33 <button id="start">Iniciar GPS</button>34 <button class="secondary" id="stop" disabled>Detener</button>35 <button class="secondary" id="download">Descargar registro</button>36 <button class="secondary" id="clear">Borrar datos</button>37 </div>38 <p id="status" role="status">Sin iniciar.</p>39 </div>40 <div class="panel stats">41 <div><div class="name">Posiciones recibidas</div><div class="value" id="count">0</div></div>42 <div><div class="name">Última posición</div><div class="value" id="last">—</div></div>43 <div><div class="name">Separación entre posiciones</div><div class="value" id="gap">—</div></div>44 <div><div class="name">Precisión del GPS</div><div class="value" id="accuracy">—</div></div>45 <div><div class="name">Visibilidad de la página</div><div class="value" id="visibility">—</div></div>46 <div><div class="name">Conexión segura</div><div class="value" id="secure">—</div></div>47 </div>48 <div class="panel">49 <strong>Últimos eventos</strong>50 <pre id="events"></pre>51 </div>52 <p>Importante: esta prueba no fuerza al navegador a trabajar en segundo plano; solo registra si realmente recibe ubicaciones. Los datos se guardan en este dispositivo y no se envían a ningún servidor. Para permisos GPS fiables, abre la página desde una URL <strong>HTTPS</strong>.</p>53 </main>54 <script>55 'use strict';56 const KEY = 'gps-background-test-v1';57 const $ = id => document.getElementById(id);58 let records = [];59 try { const stored = JSON.parse(localStorage.getItem(KEY) || '[]'); if (Array.isArray(stored)) records = stored; } catch {}60 let watchId = null;61 let active = false;62 const when = timestamp => timestamp ? new Date(timestamp).toLocaleTimeString('es-ES',{hour12:false}) : '—';63 function save(event, fields={}) {64 const entry={event, time:Date.now(), visibility:document.visibilityState,...fields};65 records.push(entry);66 if(records.length>5000) records=records.slice(-5000);67 try {localStorage.setItem(KEY, JSON.stringify(records));} catch (e) { $('status').textContent='No se pudo guardar el registro: '+e.message;}68 render();69 }70 function render(){71 const positions=records.filter(r=>r.event==='position');72 const last=positions.at(-1);73 const prev=positions.at(-2);74 $('count').textContent=positions.length.toString();75 $('last').textContent=last?when(last.time):'—';76 $('gap').textContent=last&&prev?Math.round((last.time-prev.time)/1000)+' s':'—';77 $('accuracy').textContent=last?Math.round(last.accuracy)+' m':'—';78 $('visibility').textContent=document.visibilityState;79 $('secure').textContent=window.isSecureContext?'Sí':'No';80 $('events').textContent=records.slice(-45).reverse().map(r=>81 `${when(r.time)} ${r.visibility} ${r.event}`+82 (r.event==='position'?` | ${r.lat.toFixed(6)}, ${r.lon.toFixed(6)} | ±${Math.round(r.accuracy)} m | GPS ${when(r.gpsTime)}`:'')+83 (r.event==='error'?` | ${r.code}: ${r.message}`:'')84 ).join('n') || '(Aún no hay eventos)';85 }86 function setActive(value){active=value;$('start').disabled=value;$('stop').disabled=!value;}87 $('start').addEventListener('click',()=>{88 if(!navigator.geolocation){$('status').textContent='Geolocalización no disponible. Utiliza HTTPS en Chrome.'; save('unsupported');return;}89 if(active)return;90 setActive(true);91 $('status').textContent='Solicitando permiso / esperando la primera posición…';92 save('start',{userAgent:navigator.userAgent});93 watchId=navigator.geolocation.watchPosition(94 p=>{95 $('status').textContent='GPS activo: última posición '+when(Date.now());96 save('position',{gpsTime:p.timestamp,lat:p.coords.latitude,lon:p.coords.longitude,accuracy:p.coords.accuracy,speed:p.coords.speed,heading:p.coords.heading});97 },98 e=>{99 $('status').textContent='Error GPS ('+e.code+'): '+e.message;100 save('error',{code:e.code,message:e.message});101 if(e.code===1){setActive(false); watchId=null;}102 },103 {enableHighAccuracy:true,maximumAge:0,timeout:20000}104 );105 });106 $('stop').addEventListener('click',()=>{107 if(watchId!==null)navigator.geolocation.clearWatch(watchId);108 watchId=null;setActive(false);save('stop');$('status').textContent='Detenido.';109 });110 $('clear').addEventListener('click',()=>{111 records=[];localStorage.removeItem(KEY); render();$('status').textContent='Datos borrados.';112 });113 $('download').addEventListener('click',()=>{114 const blob=new Blob([JSON.stringify({exportedAt:new Date().toISOString(),records},null,2)],{type:'application/json'});115 const url=URL.createObjectURL(blob);116 const a=document.createElement('a');a.href=url;a.download='gps-test-'+new Date().toISOString().replace(/[:.]/g,'-')+'.json';117 document.body.append(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1000);118 });119 document.addEventListener('visibilitychange',()=>save('visibilitychange'));120 window.addEventListener('pagehide',()=>save('pagehide'));121 window.addEventListener('pageshow',()=>{render();});122 render();123 </script>124 </body>125 </html>126 Enlace
El enlace para compartir es:

