fix(boot): try/catch defensivo + migration btDevices + alert crash v1.10.16
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Karlão reportou: APK v1.10.15 crasha no boot mesmo após desinstalar e reinstalar. Significa bug no código, não state corrompido. Fix preventivo: - Boot IIFE wrapped em try/catch master - Cada init (loadState, tracking, anchor, battery, sw, sensors, rt, gcal) agora em try individual — falha de um não derruba o resto - Migration defensiva de state.btDevices: filtra entries inválidas (null, sem id, etc) - Se loadState crashar (state corrupto), reseta localStorage - Crash master no try-catch chama alert() nativo + localStorage.clear() pra recovery automático na próxima abertura Quando Karlão atualizar pra v1.10.16, vai aparecer mensagem específica do erro (se ainda houver) — daí descubro causa exata em vez de adivinhar. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
18bade8768
commit
ca66a6995f
6 changed files with 73 additions and 39 deletions
|
|
@ -3747,22 +3747,39 @@ async function updateStorageInfo(){
|
||||||
}
|
}
|
||||||
|
|
||||||
(async()=>{
|
(async()=>{
|
||||||
await openDB();loadState();bindHeader();await renderAll();
|
// Wrapper try/catch pra capturar crash no boot (Capacitor WebView pode fechar silenciosamente)
|
||||||
document.getElementById('fab').style.display='none';
|
try{
|
||||||
loadTrackingState();
|
await openDB();
|
||||||
loadAnchorState();
|
try{loadState()}catch(e){console.error('[boot] loadState',e);try{localStorage.removeItem(STORAGE_KEY)}catch{}/* corrupt state — reset */}
|
||||||
initBattery();
|
// Migration defensiva: limpa entries inválidas em state.btDevices
|
||||||
initServiceWorker();
|
if(state.btDevices&&Array.isArray(state.btDevices)){
|
||||||
initSensorWidget();
|
state.btDevices=state.btDevices.filter(d=>d&&typeof d==='object'&&d.id);
|
||||||
// Realtime sync: conecta WebSocket se cloud configurada
|
}else{
|
||||||
setSyncStatus(cloudConfigured()?'syncing':'disabled');
|
state.btDevices=[];
|
||||||
if(cloudConfigured()){rtConnect();refreshGoogleStatus()}
|
}
|
||||||
// tenta auto-fetch do tempo após pequeno delay
|
bindHeader();
|
||||||
setTimeout(maybeAutoFetchWeather,3000);
|
await renderAll();
|
||||||
// Welcome screen — só pra usuários sem login
|
try{document.getElementById('fab').style.display='none'}catch(e){}
|
||||||
setTimeout(maybeShowWelcome,300);
|
try{loadTrackingState()}catch(e){console.error('[boot] tracking',e)}
|
||||||
// Retoma polling do OAuth se app foi morto durante login Google
|
try{loadAnchorState()}catch(e){console.error('[boot] anchor',e)}
|
||||||
setTimeout(resumePollingIfPending,500);
|
try{initBattery()}catch(e){console.error('[boot] battery',e)}
|
||||||
|
try{initServiceWorker()}catch(e){console.error('[boot] sw',e)}
|
||||||
|
try{initSensorWidget()}catch(e){console.error('[boot] sensors',e)}
|
||||||
|
try{setSyncStatus(cloudConfigured()?'syncing':'disabled')}catch(e){}
|
||||||
|
if(cloudConfigured()){
|
||||||
|
try{rtConnect()}catch(e){console.error('[boot] rt',e)}
|
||||||
|
try{refreshGoogleStatus()}catch(e){console.error('[boot] gcal',e)}
|
||||||
|
}
|
||||||
|
setTimeout(()=>{try{maybeAutoFetchWeather()}catch(e){}},3000);
|
||||||
|
setTimeout(()=>{try{maybeShowWelcome()}catch(e){}},300);
|
||||||
|
setTimeout(()=>{try{resumePollingIfPending()}catch(e){}},500);
|
||||||
|
}catch(e){
|
||||||
|
// Crash no boot — mostra alert nativo (sobrevive Capacitor crash) + tenta auto-recovery
|
||||||
|
const msg='Boot error: '+(e.message||e)+'\n'+(e.stack||'').slice(0,300);
|
||||||
|
console.error('[BOOT CRASH]',e);
|
||||||
|
try{alert(msg)}catch{}
|
||||||
|
try{localStorage.clear()}catch{}
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
// Re-tenta init Google Sign-In quando o script async carrega
|
// Re-tenta init Google Sign-In quando o script async carrega
|
||||||
window.addEventListener('load',()=>setTimeout(()=>{if(document.getElementById('welcome-screen').style.display==='flex')initGoogleSignIn()},500));
|
window.addEventListener('load',()=>setTimeout(()=>{if(document.getElementById('welcome-screen').style.display==='flex')initGoogleSignIn()},500));
|
||||||
|
|
@ -6457,7 +6474,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.15';
|
const APP_VERSION='1.10.16';
|
||||||
function renderBluetoothCard(){
|
function renderBluetoothCard(){
|
||||||
const el=document.getElementById('bt-list');
|
const el=document.getElementById('bt-list');
|
||||||
const supportEl=document.getElementById('bt-support');
|
const supportEl=document.getElementById('bt-support');
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ android {
|
||||||
applicationId "br.com.pontualtech.shivao"
|
applicationId "br.com.pontualtech.shivao"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 28
|
versionCode 29
|
||||||
versionName "1.10.15"
|
versionName "1.10.16"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "shivao-mobile",
|
"name": "shivao-mobile",
|
||||||
"version": "1.10.15",
|
"version": "1.10.16",
|
||||||
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -3747,22 +3747,39 @@ async function updateStorageInfo(){
|
||||||
}
|
}
|
||||||
|
|
||||||
(async()=>{
|
(async()=>{
|
||||||
await openDB();loadState();bindHeader();await renderAll();
|
// Wrapper try/catch pra capturar crash no boot (Capacitor WebView pode fechar silenciosamente)
|
||||||
document.getElementById('fab').style.display='none';
|
try{
|
||||||
loadTrackingState();
|
await openDB();
|
||||||
loadAnchorState();
|
try{loadState()}catch(e){console.error('[boot] loadState',e);try{localStorage.removeItem(STORAGE_KEY)}catch{}/* corrupt state — reset */}
|
||||||
initBattery();
|
// Migration defensiva: limpa entries inválidas em state.btDevices
|
||||||
initServiceWorker();
|
if(state.btDevices&&Array.isArray(state.btDevices)){
|
||||||
initSensorWidget();
|
state.btDevices=state.btDevices.filter(d=>d&&typeof d==='object'&&d.id);
|
||||||
// Realtime sync: conecta WebSocket se cloud configurada
|
}else{
|
||||||
setSyncStatus(cloudConfigured()?'syncing':'disabled');
|
state.btDevices=[];
|
||||||
if(cloudConfigured()){rtConnect();refreshGoogleStatus()}
|
}
|
||||||
// tenta auto-fetch do tempo após pequeno delay
|
bindHeader();
|
||||||
setTimeout(maybeAutoFetchWeather,3000);
|
await renderAll();
|
||||||
// Welcome screen — só pra usuários sem login
|
try{document.getElementById('fab').style.display='none'}catch(e){}
|
||||||
setTimeout(maybeShowWelcome,300);
|
try{loadTrackingState()}catch(e){console.error('[boot] tracking',e)}
|
||||||
// Retoma polling do OAuth se app foi morto durante login Google
|
try{loadAnchorState()}catch(e){console.error('[boot] anchor',e)}
|
||||||
setTimeout(resumePollingIfPending,500);
|
try{initBattery()}catch(e){console.error('[boot] battery',e)}
|
||||||
|
try{initServiceWorker()}catch(e){console.error('[boot] sw',e)}
|
||||||
|
try{initSensorWidget()}catch(e){console.error('[boot] sensors',e)}
|
||||||
|
try{setSyncStatus(cloudConfigured()?'syncing':'disabled')}catch(e){}
|
||||||
|
if(cloudConfigured()){
|
||||||
|
try{rtConnect()}catch(e){console.error('[boot] rt',e)}
|
||||||
|
try{refreshGoogleStatus()}catch(e){console.error('[boot] gcal',e)}
|
||||||
|
}
|
||||||
|
setTimeout(()=>{try{maybeAutoFetchWeather()}catch(e){}},3000);
|
||||||
|
setTimeout(()=>{try{maybeShowWelcome()}catch(e){}},300);
|
||||||
|
setTimeout(()=>{try{resumePollingIfPending()}catch(e){}},500);
|
||||||
|
}catch(e){
|
||||||
|
// Crash no boot — mostra alert nativo (sobrevive Capacitor crash) + tenta auto-recovery
|
||||||
|
const msg='Boot error: '+(e.message||e)+'\n'+(e.stack||'').slice(0,300);
|
||||||
|
console.error('[BOOT CRASH]',e);
|
||||||
|
try{alert(msg)}catch{}
|
||||||
|
try{localStorage.clear()}catch{}
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
// Re-tenta init Google Sign-In quando o script async carrega
|
// Re-tenta init Google Sign-In quando o script async carrega
|
||||||
window.addEventListener('load',()=>setTimeout(()=>{if(document.getElementById('welcome-screen').style.display==='flex')initGoogleSignIn()},500));
|
window.addEventListener('load',()=>setTimeout(()=>{if(document.getElementById('welcome-screen').style.display==='flex')initGoogleSignIn()},500));
|
||||||
|
|
@ -6457,7 +6474,7 @@ async function removeBluetoothDevice(id){
|
||||||
renderBluetoothCard();
|
renderBluetoothCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION='1.10.15';
|
const APP_VERSION='1.10.16';
|
||||||
function renderBluetoothCard(){
|
function renderBluetoothCard(){
|
||||||
const el=document.getElementById('bt-list');
|
const el=document.getElementById('bt-list');
|
||||||
const supportEl=document.getElementById('bt-support');
|
const supportEl=document.getElementById('bt-support');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Shivao Service Worker — offline real
|
// Shivao Service Worker — offline real
|
||||||
// Estratégia: shell precachado, tiles cache-first, windy network-first, /api passa direto.
|
// Estratégia: shell precachado, tiles cache-first, windy network-first, /api passa direto.
|
||||||
// Versão usada nos cache names — bumpa essa string pra invalidar caches antigos em deploys.
|
// Versão usada nos cache names — bumpa essa string pra invalidar caches antigos em deploys.
|
||||||
const VERSION = 'shivao-v1.10.15';
|
const VERSION = 'shivao-v1.10.16';
|
||||||
const SHELL_CACHE = `shivao-shell-${VERSION}`;
|
const SHELL_CACHE = `shivao-shell-${VERSION}`;
|
||||||
const TILES_CACHE = 'shivao-tiles-v1'; // separado pra não invalidar tiles em update do shell
|
const TILES_CACHE = 'shivao-tiles-v1'; // separado pra não invalidar tiles em update do shell
|
||||||
const WINDY_CACHE = `shivao-windy-${VERSION}`;
|
const WINDY_CACHE = `shivao-windy-${VERSION}`;
|
||||||
|
|
|
||||||
|
|
@ -413,7 +413,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Atalho: /apk redireciona pra última APK release no Forgejo
|
// Atalho: /apk redireciona pra última APK release no Forgejo
|
||||||
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.15/Shivao-v1.10.15.apk';
|
const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.16/Shivao-v1.10.16.apk';
|
||||||
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
|
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
|
||||||
|
|
||||||
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)
|
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue