Crea APK gratis

API del bridge JavaScript

Sensori fitness BLE

Frequenza cardiaca, velocità, cadenza, potenza e batteria dai profili standard Bluetooth Low Energy.

AppMint.beacons helper#

AppMint.beacons.startScan(options) / stopScan() / isScanning()

Esempio

Trova i beacon Bluetooth nelle vicinanze - iBeacon ed Eddystone (UID, URL e TLM) - e comunica alla pagina ciascuno circa una volta al secondo tramite l'evento appmint:beacon, con l'intensità del segnale e una distanza approssimativa.

Restituisce: startScan() → una Promise di {ok: true} oppure {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Richiede: niente da selezionare - una build il cui codice chiama beacons.startScan dichiara le autorizzazioni per la ricerca Bluetooth e per la posizione precisa (i risultati dei beacon sono dati di posizione per Android, quindi all'utente vengono chieste entrambe e Play elenca l'app come utilizzatrice della posizione).

Rileva i beacon di un solo locale:

window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'ibeacon') {
    showNearest(b.uuid, b.major, b.minor, b.distance);      // metres, a rough estimate
  } else if (b.type === 'eddystone-url') {
    offerLink(b.url);
  } else if (b.type === 'state') {
    console.log('beacon scan ' + b.state);                  // 'scanning' | 'stopped'
  } else if (b.type === 'error') {
    console.warn('beacon scan error', b.error);
  }
});

async function startRanging() {
  if (!(window.AppMint && AppMint.beacons)) return;
  var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
  if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}

Solo Eddystone, con telemetria della batteria:

AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
  if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});

Fermalo quando si lascia la schermata:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

Campi dell'evento: ogni beacon ha type, rssi, address, timestamp; iBeacon aggiunge uuid, major, minor, txPower, distance; Eddystone UID aggiunge namespace, instance, txPower, distance; URL aggiunge url; TLM aggiunge batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra gli UUID iBeacon e i namespace Eddystone (esadecimale in minuscolo).

Note: la distanza deriva dall'intensità del segnale ed è affidabile solo per vicino / lontano - muri e persone la cambiano di metri. La ricerca continua fino a stopScan() o alla chiusura dell'app.

beaconIsScanning bridge#

window.WebToApk.beaconIsScanning(): Boolean

Se è in corso una ricerca di beacon.

Esempio

Documentato insieme a AppMint.beacons - l'esempio lì mostra anche questo.

Trova i beacon Bluetooth nelle vicinanze - iBeacon ed Eddystone (UID, URL e TLM) - e comunica alla pagina ciascuno circa una volta al secondo tramite l'evento appmint:beacon, con l'intensità del segnale e una distanza approssimativa.

Restituisce: startScan() → una Promise di {ok: true} oppure {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Richiede: niente da selezionare - una build il cui codice chiama beacons.startScan dichiara le autorizzazioni per la ricerca Bluetooth e per la posizione precisa (i risultati dei beacon sono dati di posizione per Android, quindi all'utente vengono chieste entrambe e Play elenca l'app come utilizzatrice della posizione).

Rileva i beacon di un solo locale:

window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'ibeacon') {
    showNearest(b.uuid, b.major, b.minor, b.distance);      // metres, a rough estimate
  } else if (b.type === 'eddystone-url') {
    offerLink(b.url);
  } else if (b.type === 'state') {
    console.log('beacon scan ' + b.state);                  // 'scanning' | 'stopped'
  } else if (b.type === 'error') {
    console.warn('beacon scan error', b.error);
  }
});

async function startRanging() {
  if (!(window.AppMint && AppMint.beacons)) return;
  var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
  if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}

Solo Eddystone, con telemetria della batteria:

AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
  if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});

Fermalo quando si lascia la schermata:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

Campi dell'evento: ogni beacon ha type, rssi, address, timestamp; iBeacon aggiunge uuid, major, minor, txPower, distance; Eddystone UID aggiunge namespace, instance, txPower, distance; URL aggiunge url; TLM aggiunge batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra gli UUID iBeacon e i namespace Eddystone (esadecimale in minuscolo).

Note: la distanza deriva dall'intensità del segnale ed è affidabile solo per vicino / lontano - muri e persone la cambiano di metri. La ricerca continua fino a stopScan() o alla chiusura dell'app.

beaconStartScan bridge#

window.WebToApk.beaconStartScan(optionsJson: String, callbackId: String)

Avvia la rilevazione dei beacon con [optionsJson] `{uuids?, ibeacon?, eddystone?}`; risolve [callbackId] con `{ok}` oppure `{ok:false, code}`.

Esempio

Documentato insieme a AppMint.beacons - l'esempio lì mostra anche questo.

Trova i beacon Bluetooth nelle vicinanze - iBeacon ed Eddystone (UID, URL e TLM) - e comunica alla pagina ciascuno circa una volta al secondo tramite l'evento appmint:beacon, con l'intensità del segnale e una distanza approssimativa.

Restituisce: startScan() → una Promise di {ok: true} oppure {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Richiede: niente da selezionare - una build il cui codice chiama beacons.startScan dichiara le autorizzazioni per la ricerca Bluetooth e per la posizione precisa (i risultati dei beacon sono dati di posizione per Android, quindi all'utente vengono chieste entrambe e Play elenca l'app come utilizzatrice della posizione).

Rileva i beacon di un solo locale:

window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'ibeacon') {
    showNearest(b.uuid, b.major, b.minor, b.distance);      // metres, a rough estimate
  } else if (b.type === 'eddystone-url') {
    offerLink(b.url);
  } else if (b.type === 'state') {
    console.log('beacon scan ' + b.state);                  // 'scanning' | 'stopped'
  } else if (b.type === 'error') {
    console.warn('beacon scan error', b.error);
  }
});

async function startRanging() {
  if (!(window.AppMint && AppMint.beacons)) return;
  var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
  if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}

Solo Eddystone, con telemetria della batteria:

AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
  if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});

Fermalo quando si lascia la schermata:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

Campi dell'evento: ogni beacon ha type, rssi, address, timestamp; iBeacon aggiunge uuid, major, minor, txPower, distance; Eddystone UID aggiunge namespace, instance, txPower, distance; URL aggiunge url; TLM aggiunge batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra gli UUID iBeacon e i namespace Eddystone (esadecimale in minuscolo).

Note: la distanza deriva dall'intensità del segnale ed è affidabile solo per vicino / lontano - muri e persone la cambiano di metri. La ricerca continua fino a stopScan() o alla chiusura dell'app.

beaconStopScan bridge#

window.WebToApk.beaconStopScan(callbackId: String)

Ferma la rilevazione dei beacon; risolve [callbackId] con `{ok:true}`.

Esempio

Documentato insieme a AppMint.beacons - l'esempio lì mostra anche questo.

Trova i beacon Bluetooth nelle vicinanze - iBeacon ed Eddystone (UID, URL e TLM) - e comunica alla pagina ciascuno circa una volta al secondo tramite l'evento appmint:beacon, con l'intensità del segnale e una distanza approssimativa.

Restituisce: startScan() → una Promise di {ok: true} oppure {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Richiede: niente da selezionare - una build il cui codice chiama beacons.startScan dichiara le autorizzazioni per la ricerca Bluetooth e per la posizione precisa (i risultati dei beacon sono dati di posizione per Android, quindi all'utente vengono chieste entrambe e Play elenca l'app come utilizzatrice della posizione).

Rileva i beacon di un solo locale:

window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'ibeacon') {
    showNearest(b.uuid, b.major, b.minor, b.distance);      // metres, a rough estimate
  } else if (b.type === 'eddystone-url') {
    offerLink(b.url);
  } else if (b.type === 'state') {
    console.log('beacon scan ' + b.state);                  // 'scanning' | 'stopped'
  } else if (b.type === 'error') {
    console.warn('beacon scan error', b.error);
  }
});

async function startRanging() {
  if (!(window.AppMint && AppMint.beacons)) return;
  var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
  if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}

Solo Eddystone, con telemetria della batteria:

AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
  var b = e.detail;
  if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
  if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});

Fermalo quando si lascia la schermata:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

Campi dell'evento: ogni beacon ha type, rssi, address, timestamp; iBeacon aggiunge uuid, major, minor, txPower, distance; Eddystone UID aggiunge namespace, instance, txPower, distance; URL aggiunge url; TLM aggiunge batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra gli UUID iBeacon e i namespace Eddystone (esadecimale in minuscolo).

Note: la distanza deriva dall'intensità del segnale ed è affidabile solo per vicino / lontano - muri e persone la cambiano di metri. La ricerca continua fino a stopScan() o alla chiusura dell'app.

bleConnect bridge#

window.WebToApk.bleConnect(address: String)

Runtime per permBluetooth. Nessun interruttore della procedura guidata lo imposta: la build lo attiva quando il codice della pagina stessa chiama questi metodi (o Web Bluetooth). Prima di questo runtime le autorizzazioni venivano dichiarate mentre nulla nel runtime toccava un sensore, esattamente lo schema dichiarato-ma-inutile che documenta SmsBridge. I risultati arrivano come eventi `appmint:ble` / window.onAppMintBle({kind, ...}).

Descritto dal suo gruppo, sensori fitness BLE (frequenza cardiaca / velocità / cadenza / potenza / batteria), e non da solo.

Esempio

Si connette a un sensore fitness trovato con bleStartScan() e inizia a trasmettere le sue letture.

Restituisce: niente. Avanzamento e dati arrivano come eventi appmint:ble (e window.onAppMintBle): {kind:'state', state:'connecting', address}, {kind:'state', state:'connected', address}, {kind:'state', state:'ready', services:[...]}, poi {kind:'data', type, data} per ogni lettura. Richiede: Bluetooth (attivato da una build ZIP o HTML quando il tuo codice usa il bridge dei sensori) e l'autorizzazione Dispositivi nelle vicinanze, chiesta al primo utilizzo.

Passa l'address di un evento device, dal tocco dell'utente:

function connectSensor(address) {
  if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
  window.WebToApk.bleConnect(address);
}

window.onAppMintBle = function (d) {
  if (d.kind === 'state') {
    // 'connecting' | 'connected' | 'ready' | 'disconnected' (also 'scanning' / 'scan_stopped')
    showStatus(d.state);
  } else if (d.kind === 'data') {
    if (d.type === 'heart_rate')    show('bpm', d.data.bpm);
    if (d.type === 'speed_cadence') {                   // either key can be missing in one packet
      if (d.data.speedKmh !== undefined)   show('speed', d.data.speedKmh.toFixed(1) + ' km/h');
      if (d.data.cadenceRpm !== undefined) show('cadence', Math.round(d.data.cadenceRpm) + ' rpm');
    }
    if (d.type === 'power')   show('power', d.data.watts + ' W');
    if (d.type === 'running') show('pace', d.data.speedKmh.toFixed(1) + ' km/h, ' + d.data.cadenceSpm + ' spm');
    if (d.type === 'battery') show('battery', d.data.percent + '%');
  } else if (d.kind === 'error') {
    showStatus('Could not connect: ' + d.error);
  }
};

Ricorda il sensore che si è connesso e ricollegati la prossima volta senza una ricerca:

var SAVED_KEY = 'hrStrapAddress';

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind === 'state' && d.state === 'connected') localStorage.setItem(SAVED_KEY, d.address);
  if (d.kind === 'error' && d.error === 'invalid_address') localStorage.removeItem(SAVED_KEY);
});

document.getElementById('start-workout').addEventListener('click', function () {
  if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
  var address = localStorage.getItem(SAVED_KEY);
  if (address) window.WebToApk.bleConnect(address);
  else window.WebToApk.bleStartScan();   // first time: let the user pick a sensor
});

Segui una sessione di frequenza cardiaca (media, massimo, contatto della fascia) dalle letture:

var beats = 0, sum = 0, max = 0;

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind === 'state' && d.state === 'ready' && d.services.length === 0) {
    showStatus('This sensor has no heart rate, speed, power or battery service.');
  }
  if (d.kind !== 'data' || d.type !== 'heart_rate') return;
  if (d.data.contact === false) {          // only sent by straps that report skin contact
    showStatus('Wet the strap: no skin contact');
    return;
  }
  beats++; sum += d.data.bpm; max = Math.max(max, d.data.bpm);
  show('bpm', d.data.bpm);
  show('avg', Math.round(sum / beats));
  show('max', max);
});

Note: un sensore alla volta: connettersi ferma qualsiasi ricerca e prima scollega il sensore precedente (ricevi il suo disconnected). ready.services elenca gli UUID completi dei servizi supportati che questo sensore ha. Il primo pacchetto di velocità/cadenza dopo la connessione non invia nulla - velocità e cadenza hanno bisogno di due pacchetti per essere calcolate. heart_rate porta anche rrIntervalsMs (intervalli battito su battito in ms, quando la fascia li invia), energyKj e contact quando la fascia li riporta; power porta cadenceRpm dal secondo pacchetto in poi quando il misuratore invia dati della pedivella. Errori: not_enabled, permission_denied, bluetooth_unavailable, invalid_address. Se il sensore esce dalla portata ricevi {kind:'state', state:'disconnected', address}.

bleDisconnect bridge#

window.WebToApk.bleDisconnect()

Runtime per permBluetooth. Nessun interruttore della procedura guidata lo imposta: la build lo attiva quando il codice della pagina stessa chiama questi metodi (o Web Bluetooth). Prima di questo runtime le autorizzazioni venivano dichiarate mentre nulla nel runtime toccava un sensore, esattamente lo schema dichiarato-ma-inutile che documenta SmsBridge. I risultati arrivano come eventi `appmint:ble` / window.onAppMintBle({kind, ...}).

Descritto dal suo gruppo, sensori fitness BLE (frequenza cardiaca / velocità / cadenza / potenza / batteria), e non da solo.

Esempio

Disconnette il sensore fitness connesso con bleConnect().

Restituisce: niente. Se un sensore era connesso, segue un evento appmint:ble {kind:'state', state:'disconnected'}. Richiede: Bluetooth (attivato da una build ZIP o HTML quando il tuo codice usa il bridge dei sensori); senza di esso la chiamata non fa nulla.

document.getElementById('end-workout').addEventListener('click', function () {
  if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
    window.WebToApk.bleDisconnect();
  }
});

window.addEventListener('appmint:ble', function (e) {
  if (e.detail.kind === 'state' && e.detail.state === 'disconnected') {
    showStatus('Sensor disconnected');
  }
});

Riconnettiti da solo quando il sensore si disconnette, ma non quando è stato l'utente a terminare l'allenamento:

var lastAddress = null, userEnded = false, retries = 0;

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind !== 'state') return;
  if (d.state === 'connected') { lastAddress = d.address; userEnded = false; retries = 0; }
  // Only a drop caused by the sensor carries an address.
  if (d.state === 'disconnected' && d.address && !userEnded && lastAddress && retries < 3) {
    retries++;
    showStatus('Sensor lost, reconnecting (' + retries + '/3)...');
    setTimeout(function () { window.WebToApk.bleConnect(lastAddress); }, 3000);
  }
});

function endWorkout() {
  userEnded = true;
  if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
    window.WebToApk.bleDisconnect();
  }
}

Scollega e dimentica il sensore salvato da una schermata delle impostazioni:

document.getElementById('forget-sensor').addEventListener('click', function () {
  localStorage.removeItem('hrStrapAddress');   // wherever your app saved the address
  if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
    window.WebToApk.bleDisconnect();
  }
  showStatus('Sensor forgotten. Tap Scan to pair a new one.');
});

Note: l'evento disconnected che provochi tu non ha address; quello causato dal sensore (fuori portata, spento) ce l'ha. L'app si disconnette anche quando si chiude.

bleSetWheelCircumference bridge#

window.WebToApk.bleSetWheelCircumference(mm: Int)

Runtime per permBluetooth. Nessun interruttore della procedura guidata lo imposta: la build lo attiva quando il codice della pagina stessa chiama questi metodi (o Web Bluetooth). Prima di questo runtime le autorizzazioni venivano dichiarate mentre nulla nel runtime toccava un sensore, esattamente lo schema dichiarato-ma-inutile che documenta SmsBridge. I risultati arrivano come eventi `appmint:ble` / window.onAppMintBle({kind, ...}).

Descritto dal suo gruppo, sensori fitness BLE (frequenza cardiaca / velocità / cadenza / potenza / batteria), e non da solo.

Esempio

Imposta la dimensione della ruota della bici (circonferenza in millimetri) usata per trasformare i giri di ruota di un sensore di velocità in km/h.

Restituisce: niente. Richiede: niente per chiamarlo; le letture di velocità richiedono un sensore di velocità per bici connesso (vedi bleConnect).

// 2096 mm = 700x23c (the default). 2105 = 700x25c, 2136 = 700x28c, 2070 = 26x2.0 MTB.
function setWheel(mm) {
  if (window.WebToApk && typeof window.WebToApk.bleSetWheelCircumference === 'function') {
    window.WebToApk.bleSetWheelCircumference(mm);
  }
}

document.getElementById('wheel').addEventListener('change', function (e) {
  setWheel(parseInt(e.target.value, 10));
});

Applica la dimensione della ruota salvata dal ciclista a ogni connessione, perché l'impostazione non sopravvive a un riavvio:

function connectBike(address) {
  if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
  var mm = parseInt(localStorage.getItem('wheelMm'), 10) || 2096;
  window.WebToApk.bleSetWheelCircumference(mm);
  window.WebToApk.bleConnect(address);
}

Calibra da una misura reale (un giro completo di ruota, in cm) e controlla tu l'intervallo, perché un valore fuori intervallo viene ignorato senza errore:

document.getElementById('save-rollout').addEventListener('click', function () {
  var mm = Math.round(parseFloat(document.getElementById('rollout-cm').value) * 10);
  if (!(mm >= 500 && mm <= 4000)) {
    showStatus('Enter a roll-out between 50 and 400 cm.');
    return;
  }
  localStorage.setItem('wheelMm', String(mm));
  if (window.WebToApk && typeof window.WebToApk.bleSetWheelCircumference === 'function') {
    window.WebToApk.bleSetWheelCircumference(mm);   // applies to the next speed reading
  }
  showStatus('Wheel set to ' + mm + ' mm');
});

Note: i valori fuori da 500-4000 mm vengono ignorati in silenzio (resta il vecchio valore). L'impostazione dura finché l'app non si chiude, quindi impostala di nuovo a ogni avvio, per esempio subito prima di bleConnect(). Cambia speedKmh nei dati speed_cadence di appmint:ble; la cadenza non è influenzata.

bleStartScan bridge#

window.WebToApk.bleStartScan()

Runtime per permBluetooth. Nessun interruttore della procedura guidata lo imposta: la build lo attiva quando il codice della pagina stessa chiama questi metodi (o Web Bluetooth). Prima di questo runtime le autorizzazioni venivano dichiarate mentre nulla nel runtime toccava un sensore, esattamente lo schema dichiarato-ma-inutile che documenta SmsBridge. I risultati arrivano come eventi `appmint:ble` / window.onAppMintBle({kind, ...}).

Descritto dal suo gruppo, sensori fitness BLE (frequenza cardiaca / velocità / cadenza / potenza / batteria), e non da solo.

Esempio

Cerca per 15 secondi i sensori fitness Bluetooth nelle vicinanze (frequenza cardiaca, velocità/cadenza della bici, potenza, footpod per la corsa).

Restituisce: niente. I risultati arrivano come eventi appmint:ble (e window.onAppMintBle(detail)): uno {kind:'device', address, name, sensors, rssi} per ogni sensore trovato, più {kind:'state', state:'scanning'} all'inizio e {kind:'state', state:'scan_stopped'} alla fine. Richiede: Bluetooth. Non c'è un interruttore: quando crei da uno ZIP o da una pagina HTML, la build attiva da sola il Bluetooth se il tuo codice chiama bleStartScan / bleConnect o usa navigator.bluetooth. Una build per sito web (URL) non può attivarlo. La prima ricerca chiede all'utente l'autorizzazione Dispositivi nelle vicinanze (Posizione su Android 11 e precedenti).

Prima ascolta, poi avvia la ricerca dal tocco su un pulsante:

var found = {};

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind === 'device') {
    found[d.address] = d;
    // d.sensors: any of 'heart_rate', 'speed_cadence', 'power', 'running'
    addRow(d.address, (d.name || 'Unnamed sensor') + ' ' + d.sensors.join(', ') + ' (' + d.rssi + ' dBm)');
  } else if (d.kind === 'state' && d.state === 'scanning') {
    showStatus('Looking for sensors...');
  } else if (d.kind === 'state' && d.state === 'scan_stopped') {
    showStatus(Object.keys(found).length ? 'Pick a sensor' : 'No sensors found. Wake the sensor and try again.');
  } else if (d.kind === 'error') {
    showStatus('Bluetooth error: ' + d.error);
  }
});

document.getElementById('scan').addEventListener('click', function () {
  if (window.WebToApk && typeof window.WebToApk.bleStartScan === 'function') {
    found = {};
    window.WebToApk.bleStartScan();
  } else {
    showStatus('Sensors work in the installed app only.');
  }
});

Associa automaticamente la fascia cardio più forte quando la ricerca termina:

var best = null, pairing = false;

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (!pairing) return;
  if (d.kind === 'device' && d.sensors.indexOf('heart_rate') !== -1) {
    if (!best || d.rssi > best.rssi) best = d;   // closer strap = higher (less negative) rssi
  } else if (d.kind === 'state' && d.state === 'scan_stopped') {
    pairing = false;
    if (best) window.WebToApk.bleConnect(best.address);
    else showStatus('No heart-rate strap found. Put it on and try again.');
  }
});

document.getElementById('pair-hr').addEventListener('click', function () {
  if (!window.WebToApk || typeof window.WebToApk.bleStartScan !== 'function') return;
  best = null;
  pairing = true;
  window.WebToApk.bleStartScan();
});

Trasforma ogni errore di ricerca in un messaggio su cui l'utente può agire:

var SCAN_HELP = {
  not_enabled: 'This app was built without Bluetooth.',
  permission_denied: 'Allow Nearby devices for this app in Settings to find sensors.',
  bluetooth_unavailable: 'This phone has no Bluetooth.',
  bluetooth_off: 'Turn Bluetooth on, then tap Scan again.',
  scan_failed: 'The scan could not start. Wait a moment and try again.'
};

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind !== 'error') return;
  var text = SCAN_HELP[d.error] || ('Bluetooth error: ' + d.error);
  if (d.code !== undefined) text += ' (code ' + d.code + ')';
  showStatus(text);
  document.getElementById('scan').disabled = false;
});

Note: codici di errore in {kind:'error', error}: not_enabled (la build non ha il Bluetooth), permission_denied, bluetooth_unavailable (nessun adattatore), bluetooth_off, scan_failed (può portare il code di Android). La ricerca segnala solo i dispositivi che annunciano uno dei quattro servizi fitness, e ogni dispositivo una sola volta per ricerca. Avviare una nuova ricerca ferma la vecchia. Usa o il listener appmint:ble o window.onAppMintBle, non entrambi - entrambi vengono chiamati per ogni messaggio.

bleStopScan bridge#

window.WebToApk.bleStopScan()

Runtime per permBluetooth. Nessun interruttore della procedura guidata lo imposta: la build lo attiva quando il codice della pagina stessa chiama questi metodi (o Web Bluetooth). Prima di questo runtime le autorizzazioni venivano dichiarate mentre nulla nel runtime toccava un sensore, esattamente lo schema dichiarato-ma-inutile che documenta SmsBridge. I risultati arrivano come eventi `appmint:ble` / window.onAppMintBle({kind, ...}).

Descritto dal suo gruppo, sensori fitness BLE (frequenza cardiaca / velocità / cadenza / potenza / batteria), e non da solo.

Esempio

Ferma una ricerca di sensori avviata con bleStartScan() prima che i suoi 15 secondi siano trascorsi.

Restituisce: niente. Se una ricerca era in corso, segue un evento appmint:ble {kind:'state', state:'scan_stopped'}. Richiede: Bluetooth (attivato da una build ZIP o HTML quando il tuo codice usa il bridge dei sensori); senza di esso la chiamata non fa nulla.

window.addEventListener('appmint:ble', function (e) {
  if (e.detail.kind === 'state' && e.detail.state === 'scan_stopped') {
    document.getElementById('scan').disabled = false;
  }
});

document.getElementById('stop-scan').addEventListener('click', function () {
  if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
    window.WebToApk.bleStopScan();
  }
});

Fermati subito appena compare il tipo di sensore che ti serve:

window.addEventListener('appmint:ble', function (e) {
  var d = e.detail;
  if (d.kind === 'device' && d.sensors.indexOf('power') !== -1) {
    if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
      window.WebToApk.bleStopScan();   // no need to wait the full 15 seconds
    }
    showPowerMeter(d.address, d.name || 'Power meter');
  }
});

Smetti di cercare quando l'utente chiude la schermata di associazione o lascia l'app:

function stopLooking() {
  if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
    window.WebToApk.bleStopScan();   // safe even if the scan already ended
  }
}

document.getElementById('close-pairing').addEventListener('click', function () {
  stopLooking();
  document.getElementById('pairing-sheet').hidden = true;
});

document.addEventListener('visibilitychange', function () {
  if (document.hidden) stopLooking();
});

Note: raramente ti serve: la ricerca si ferma da sola dopo 15 secondi e la ferma anche bleConnect(). Chiamarlo quando nessuna ricerca è in corso è sicuro e non invia alcun evento.

Generato dal runtime dell'app e dai suoi file di esempio a ogni build della documentazione. Leggilo in Markdown · Tutte le famiglie.

Verificato rispetto al bridge distribuito il 22/10/2026.