From 840f0b0dc5aa4835a58e24d60d9e9f395f8c1918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?PontualTech=20/=20Karl=C3=A3o?= Date: Wed, 29 Apr 2026 06:59:35 -0300 Subject: [PATCH] =?UTF-8?q?fix(ble):=20remove=20requestMtu/requestConnecti?= =?UTF-8?q?onPriority=20=E2=80=94=20crash=20em=20plugin=20v6.x=20v1.10.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug crítico v1.10.3: app crashava ao parear ou clicar Re-ler. Causa: chamadas a ble.requestConnectionPriority() e ble.requestMtu() não existem no @capacitor-community/bluetooth-le v6.1.0 (foram adicionadas em v7+). Sem o método, o plugin lança exception nativa não-tratada que escapa do try/catch JS e derruba o WebView Capacitor. Fix: - Remove requestMtu + requestConnectionPriority - getServices() chamado UMA vez (não no loop por vendor) - Filtra services por prefixo vendor (ff00, fff0, ffe0, 0203) - Lista todos chars descobertos com properties no diagnóstico - Loga "getServices retornou N services" pra confirmar que enumeração rodou Co-Authored-By: Claude Opus 4.7 (1M context) --- app/diario-bordo.html | 63 +++++++++++++++------------------ mobile/android/app/build.gradle | 4 +-- mobile/package.json | 2 +- server/public/index.html | 63 +++++++++++++++------------------ server/src/index.js | 2 +- 5 files changed, 60 insertions(+), 74 deletions(-) diff --git a/app/diario-bordo.html b/app/diario-bordo.html index a59c086..b3b0e5c 100644 --- a/app/diario-bordo.html +++ b/app/diario-bordo.html @@ -5999,42 +5999,35 @@ async function bmsProbeAndAttach(deviceId,deviceName){ const ble=window.Capacitor.Plugins.BluetoothLe; try{ setBleDiag(`📦 Shivao v${APP_VERSION} · Probe iniciado`,'info'); - // Tenta aumentar MTU pra 247 (alguns BMS exigem) - try{ - const r=await ble.requestConnectionPriority({deviceId,connectionPriority:'high'}); - setBleDiag('Connection priority HIGH ok','info'); - }catch(e){setBleDiag('connection priority skip','info')} - try{ - await ble.requestMtu({deviceId,mtu:247}); - setBleDiag('MTU bumped pra 247','info'); - }catch(e){setBleDiag('MTU bump skip','info')} + // MTU/priority bump removidos — não existem no plugin v6.x (causam crash nativo) + // Caso o usuário tenha plugin v7+ no futuro, podemos verificar typeof ble.requestMtu==='function' setBleDiag('🔍 Enumerando characteristics...','info'); - // Tenta serviços vendor: ff00, fff0 (Daly), ffe0 (JK), 0203 - const VENDOR_SVCS=[ - '0000ff00-0000-1000-8000-00805f9b34fb', - '0000fff0-0000-1000-8000-00805f9b34fb', - '0000ffe0-0000-1000-8000-00805f9b34fb', - '00000203-0000-1000-8000-00805f9b34fb', - ]; + const VENDOR_PREFIXES=['0000ff00','0000fff0','0000ffe0','00000203']; let notifyChar=null,writeChar=null,foundService=null; - for(const svcId of VENDOR_SVCS){ - try{ - const r=await ble.getServices({deviceId}); - const svcs=r.services||r||[]; - const svc=svcs.find(s=>(s.uuid||'').toLowerCase()===svcId); - if(!svc)continue; - const chars=svc.characteristics||[]; - if(chars.length===0)continue; - setBleDiag(`Service ${svcId.slice(4,8)} · ${chars.length} chars`,'info'); - for(const c of chars){ - const props=c.properties||{}; - const propsStr=[props.notify&&'notify',props.indicate&&'indicate',props.write&&'write',props.writeWithoutResponse&&'wnr',props.read&&'read'].filter(Boolean).join(','); - setBleDiag(` ${(c.uuid||'').slice(4,8)} [${propsStr}]`,'info'); - if(!notifyChar&&(props.notify||props.indicate)){notifyChar=c.uuid;foundService=svc.uuid} - if(!writeChar&&(props.write||props.writeWithoutResponse))writeChar=c.uuid; - } - if(notifyChar&&writeChar)break; - }catch(e){} + let allSvcs=[]; + try{ + const r=await ble.getServices({deviceId}); + allSvcs=r.services||r||[]; + }catch(e){ + setBleDiag('getServices erro: '+(e.message||e.errorMessage||'?'),'err'); + return false; + } + setBleDiag(`getServices retornou ${allSvcs.length} services`,'info'); + // Filtra apenas vendor services + for(const svc of allSvcs){ + const svcUuid=(svc.uuid||'').toLowerCase(); + if(!VENDOR_PREFIXES.some(p=>svcUuid.startsWith(p)))continue; + const chars=svc.characteristics||[]; + setBleDiag(`Svc ${svcUuid.slice(4,8)} · ${chars.length} chars`,'info'); + for(const c of chars){ + const props=c.properties||{}; + const cUuid=(c.uuid||'').toLowerCase(); + const propsStr=[props.notify&&'notify',props.indicate&&'indicate',props.write&&'write',props.writeWithoutResponse&&'wnr',props.read&&'read'].filter(Boolean).join(',')||'?'; + setBleDiag(` ${cUuid.slice(4,8)} [${propsStr}]`,'info'); + if(!notifyChar&&(props.notify||props.indicate)){notifyChar=cUuid;foundService=svcUuid} + if(!writeChar&&(props.write||props.writeWithoutResponse))writeChar=cUuid; + } + if(notifyChar&&writeChar)break; } if(!notifyChar||!writeChar){ setBleDiag('Não achei chars notify+write em services vendor','err'); @@ -6254,7 +6247,7 @@ async function removeBluetoothDevice(id){ renderBluetoothCard(); } -const APP_VERSION='1.10.3'; +const APP_VERSION='1.10.4'; function renderBluetoothCard(){ const el=document.getElementById('bt-list'); const supportEl=document.getElementById('bt-support'); diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index d70726e..3f8b370 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "br.com.pontualtech.shivao" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 19 - versionName "1.10.3" + versionCode 20 + versionName "1.10.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/mobile/package.json b/mobile/package.json index 714331a..031baff 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -1,6 +1,6 @@ { "name": "shivao-mobile", - "version": "1.10.3", + "version": "1.10.4", "description": "Shivao app nativo (Capacitor wrapper Android/iOS)", "main": "index.js", "type": "module", diff --git a/server/public/index.html b/server/public/index.html index a59c086..b3b0e5c 100644 --- a/server/public/index.html +++ b/server/public/index.html @@ -5999,42 +5999,35 @@ async function bmsProbeAndAttach(deviceId,deviceName){ const ble=window.Capacitor.Plugins.BluetoothLe; try{ setBleDiag(`📦 Shivao v${APP_VERSION} · Probe iniciado`,'info'); - // Tenta aumentar MTU pra 247 (alguns BMS exigem) - try{ - const r=await ble.requestConnectionPriority({deviceId,connectionPriority:'high'}); - setBleDiag('Connection priority HIGH ok','info'); - }catch(e){setBleDiag('connection priority skip','info')} - try{ - await ble.requestMtu({deviceId,mtu:247}); - setBleDiag('MTU bumped pra 247','info'); - }catch(e){setBleDiag('MTU bump skip','info')} + // MTU/priority bump removidos — não existem no plugin v6.x (causam crash nativo) + // Caso o usuário tenha plugin v7+ no futuro, podemos verificar typeof ble.requestMtu==='function' setBleDiag('🔍 Enumerando characteristics...','info'); - // Tenta serviços vendor: ff00, fff0 (Daly), ffe0 (JK), 0203 - const VENDOR_SVCS=[ - '0000ff00-0000-1000-8000-00805f9b34fb', - '0000fff0-0000-1000-8000-00805f9b34fb', - '0000ffe0-0000-1000-8000-00805f9b34fb', - '00000203-0000-1000-8000-00805f9b34fb', - ]; + const VENDOR_PREFIXES=['0000ff00','0000fff0','0000ffe0','00000203']; let notifyChar=null,writeChar=null,foundService=null; - for(const svcId of VENDOR_SVCS){ - try{ - const r=await ble.getServices({deviceId}); - const svcs=r.services||r||[]; - const svc=svcs.find(s=>(s.uuid||'').toLowerCase()===svcId); - if(!svc)continue; - const chars=svc.characteristics||[]; - if(chars.length===0)continue; - setBleDiag(`Service ${svcId.slice(4,8)} · ${chars.length} chars`,'info'); - for(const c of chars){ - const props=c.properties||{}; - const propsStr=[props.notify&&'notify',props.indicate&&'indicate',props.write&&'write',props.writeWithoutResponse&&'wnr',props.read&&'read'].filter(Boolean).join(','); - setBleDiag(` ${(c.uuid||'').slice(4,8)} [${propsStr}]`,'info'); - if(!notifyChar&&(props.notify||props.indicate)){notifyChar=c.uuid;foundService=svc.uuid} - if(!writeChar&&(props.write||props.writeWithoutResponse))writeChar=c.uuid; - } - if(notifyChar&&writeChar)break; - }catch(e){} + let allSvcs=[]; + try{ + const r=await ble.getServices({deviceId}); + allSvcs=r.services||r||[]; + }catch(e){ + setBleDiag('getServices erro: '+(e.message||e.errorMessage||'?'),'err'); + return false; + } + setBleDiag(`getServices retornou ${allSvcs.length} services`,'info'); + // Filtra apenas vendor services + for(const svc of allSvcs){ + const svcUuid=(svc.uuid||'').toLowerCase(); + if(!VENDOR_PREFIXES.some(p=>svcUuid.startsWith(p)))continue; + const chars=svc.characteristics||[]; + setBleDiag(`Svc ${svcUuid.slice(4,8)} · ${chars.length} chars`,'info'); + for(const c of chars){ + const props=c.properties||{}; + const cUuid=(c.uuid||'').toLowerCase(); + const propsStr=[props.notify&&'notify',props.indicate&&'indicate',props.write&&'write',props.writeWithoutResponse&&'wnr',props.read&&'read'].filter(Boolean).join(',')||'?'; + setBleDiag(` ${cUuid.slice(4,8)} [${propsStr}]`,'info'); + if(!notifyChar&&(props.notify||props.indicate)){notifyChar=cUuid;foundService=svcUuid} + if(!writeChar&&(props.write||props.writeWithoutResponse))writeChar=cUuid; + } + if(notifyChar&&writeChar)break; } if(!notifyChar||!writeChar){ setBleDiag('Não achei chars notify+write em services vendor','err'); @@ -6254,7 +6247,7 @@ async function removeBluetoothDevice(id){ renderBluetoothCard(); } -const APP_VERSION='1.10.3'; +const APP_VERSION='1.10.4'; function renderBluetoothCard(){ const el=document.getElementById('bt-list'); const supportEl=document.getElementById('bt-support'); diff --git a/server/src/index.js b/server/src/index.js index 3f444b2..1148743 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -347,7 +347,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => { }); // Atalho: /apk redireciona pra última APK release no Forgejo -const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.3/Shivao-v1.10.3.apk'; +const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.10.4/Shivao-v1.10.4.apk'; 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)