API del bridge JavaScript
Telefono, SMS e registro chiamate
Effettuare una chiamata, inviare o preparare un messaggio e leggere la cronologia. Ognuna di queste operazioni richiede un'autorizzazione e Play fa domande al riguardo.
composeSms bridge#
window.WebToApk.composeSms(phoneNumber: String, message: String): Boolean
Apre l'app SMS dell'utente con il messaggio giĂ compilato. Non richiede autorizzazioni e non puĂČ essere rifiutato da Play: Ăš l'impostazione giusta per tutto ciĂČ che non Ăš automatico. Restituisce false quando il telefono non ha un'app SMS (o non Ăš stato possibile aprirla).
Esempio
Apre l'app SMS dell'utente con numero e testo giĂ inseriti. L'utente preme invio.
Restituisce: true quando l'app SMS si Ăš aperta, false quando il telefono non ha un'app SMS o non Ăš stato possibile aprirla (sincrono). Richiede: niente: nessun interruttore nella build, nessuna autorizzazione.
Un pulsante "Scrivici".
document.getElementById('textUs').addEventListener('click', function () {
if (window.WebToApk && window.WebToApk.composeSms) {
var ok = WebToApk.composeSms('+911234567890', 'Hello, I need help with my order');
if (!ok) showMessage('Could not open the SMS app.');
} else {
// In a normal browser the standard sms: link does the same job.
location.href = 'sms:+911234567890?body=' + encodeURIComponent('Hello, I need help with my order');
}
});Un pulsante "Ricorda" su ogni riga di appuntamento, che precompila un promemoria al numero di quel cliente:
document.getElementById('appointments').addEventListener('click', function (e) {
var row = e.target.closest('[data-phone]');
if (!row || !(window.WebToApk && typeof window.WebToApk.composeSms === 'function')) return;
var when = new Date(Number(row.getAttribute('data-time')));
var text = 'Hi ' + row.getAttribute('data-name') + ', a reminder of your appointment on ' +
when.toLocaleDateString() + ' at ' +
when.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) + '.';
if (!WebToApk.composeSms(row.getAttribute('data-phone'), text)) {
showMessage('This phone has no SMS app.');
}
});Un modulo "Invia via SMS": quando il telefono non ha un'app SMS (false), copia il testo cosĂŹ l'utente puĂČ incollarlo altrove:
document.getElementById('smsForm').addEventListener('submit', function (e) {
e.preventDefault();
var number = document.getElementById('to').value.trim();
var text = document.getElementById('message').value;
if (!number || !text) return;
var opened = window.WebToApk && typeof window.WebToApk.composeSms === 'function' &&
WebToApk.composeSms(number, text);
if (!opened && navigator.clipboard) {
navigator.clipboard.writeText(text).then(function () {
showMessage('No SMS app here. The message was copied instead.');
});
}
});Note: Non viene inviato nulla finché l'utente non tocca invio nella propria app SMS, quindi questo metodo in sé non richiede alcuna autorizzazione SMS. Usalo per ogni messaggio che l'utente scrive o approva; usa sendSms solo quando l'app deve davvero inviare da sola. Per le app create con l'AI e le importazioni da Google AI Studio, la build analizza il tuo codice; una chiamata composeSms( non attiva SMS (lettura e invio): lo fanno solo sendSms e listSms, quindi un pulsante "Scrivici" non aggiunge autorizzazioni con restrizioni di Play.
listCallLog bridge#
window.WebToApk.listCallLog(requestId: String, limit: Int, offset: Int, sinceMillis: String)
WebToApk.listCallLog(id, limit, offset, sinceMillis) Consegnato come `appmint:calllog` / window.onAppMintCallLog.
Descritta dal suo gruppo, Registro chiamate, e non singolarmente.
Esempio
Legge la cronologia chiamate del telefono, dalla chiamata piĂč recente.
Restituisce: per ora niente. La risposta Ăš l'evento appmint:calllog (e window.onAppMintCallLog) con detail = { requestId, calls: [{ number, name, type, date, duration }] } oppure { requestId, error }. date Ăš in millisecondi dal 1970; duration Ăš in secondi. Richiede: attiva Registro chiamate (lettura) nel Passaggio 4 (Accesso) durante la creazione; all'utente viene chiesta l'autorizzazione alla prima chiamata.
Mostra le ultime 50 chiamate.
function loadCalls() {
if (!(window.WebToApk && window.WebToApk.listCallLog)) return;
var id = 'calls-' + Date.now();
window.addEventListener('appmint:calllog', function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
window.removeEventListener('appmint:calllog', handler);
if (e.detail.error) { showMessage('Call log: ' + e.detail.error); return; }
e.detail.calls.forEach(function (c) {
// c.type: incoming | outgoing | missed | voicemail | rejected | blocked | other
addRow((c.name || c.number) + ' - ' + c.type + ' - ' +
new Date(c.date).toLocaleString() + ' - ' + c.duration + 's');
});
});
WebToApk.listCallLog(id, 50, 0, '0'); // limit, offset, since (string)
}Solo le chiamate delle ultime 24 ore, usando l'hook della pagina. sinceMillis Ú una STRINGA perché il numero Ú troppo grande per l'int del bridge.
window.onAppMintCallLog = function (detail) {
if (detail.requestId !== 'today') return;
if (detail.error) return;
document.getElementById('count').textContent = detail.calls.length + ' calls today';
};
if (window.WebToApk && window.WebToApk.listCallLog) {
WebToApk.listCallLog('today', 500, 0, String(Date.now() - 24 * 60 * 60 * 1000));
}Una schermata della cronologia chiamate con un pulsante "Carica altre", che recupera 25 chiamate alla volta con offset:
var PAGE = 25, loaded = 0;
function loadMoreCalls() {
if (!(window.WebToApk && typeof window.WebToApk.listCallLog === 'function')) return;
var id = 'page-' + loaded;
window.addEventListener('appmint:calllog', function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
window.removeEventListener('appmint:calllog', handler);
if (e.detail.error) { showMessage('Call log: ' + e.detail.error); return; }
e.detail.calls.forEach(function (c) { addRow(c.name || c.number, c.type, c.date); });
loaded += e.detail.calls.length;
document.getElementById('more').hidden = e.detail.calls.length < PAGE; // last page
});
WebToApk.listCallLog(id, PAGE, loaded, '0'); // skip the calls already shown
}
document.getElementById('more').addEventListener('click', loadMoreCalls);
loadMoreCalls();Note: limit Ăš limitato a 1-2000. Errori: not_enabled, permission_denied, foreign_origin. Il registro chiamate Ăš un'autorizzazione con restrizioni di Google Play: devi presentare in Play Console una Dichiarazione sulle autorizzazioni approvata, altrimenti l'app viene rifiutata.
listSms bridge#
window.WebToApk.listSms(requestId: String, box: String, limit: Int, offset: Int)
WebToApk.composeSms(number, message) <- NESSUNA autorizzazione, apre l'app SMS WebToApk.sendSms(id, number, message, wantDelivery) WebToApk.listSms(id, "inbox"|"sent"|"draft", limit, offset) Risultati dell'invio: `appmint:sms` / window.onAppMintSms {requestId, status:"sent"|"delivered"|"failed", ok, reason?} Messaggi in arrivo: `appmint:sms-received` / window.onAppMintSmsReceived.
Descritta dal suo gruppo, SMS, e non singolarmente.
Esempio
Legge gli SMS dalla posta in arrivo, dagli inviati o dalle bozze del telefono, dal piĂč recente. Questo file mostra anche come ricevere nuovi messaggi appena arrivano.
Restituisce: per ora niente. La risposta Ăš l'evento appmint:sms (e window.onAppMintSms) con detail = { requestId, messages: [{ id, address, body, date, read, box }] }. In caso di errore: { requestId, status: 'failed', ok: false, reason }. Richiede: attiva SMS (lettura e invio) nel Passaggio 4 (Accesso) durante la creazione; all'utente viene chiesta l'autorizzazione alla prima chiamata.
Leggi gli ultimi 30 messaggi in arrivo.
function loadInbox() {
if (!(window.WebToApk && window.WebToApk.listSms)) return;
var id = 'inbox-' + Date.now();
window.addEventListener('appmint:sms', function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
window.removeEventListener('appmint:sms', handler);
if (e.detail.status === 'failed') { showMessage('Cannot read SMS: ' + e.detail.reason); return; }
e.detail.messages.forEach(function (m) {
addRow(m.address + ': ' + m.body + (m.read ? '' : ' (new)') +
' - ' + new Date(m.date).toLocaleString());
});
});
WebToApk.listSms(id, 'inbox', 30, 0); // box: 'inbox' | 'sent' | 'draft'
}Nuovi messaggi appena arrivano (appmint:sms-received, anche window.onAppMintSmsReceived). I messaggi che arrivano mentre l'app Ăš chiusa vengono conservati (gli ultimi 50) e consegnati alla tua pagina quando l'app si riapre.
window.addEventListener('appmint:sms-received', function (e) {
// e.detail = { address: '+91...', body: 'Your OTP is 4821', date: 1737000000000 }
var code = (e.detail.body.match(/\b\d{4,6}\b/) || [])[0];
if (code) document.getElementById('otp').value = code;
});
// or, as a page hook:
window.onAppMintSmsReceived = function (sms) {
console.log('SMS from ' + sms.address);
};Un tracker di spese che analizza gli ultimi 200 messaggi in arrivo in cerca di addebiti bancari e ne somma gli importi:
function scanSpending() {
if (!(window.WebToApk && typeof window.WebToApk.listSms === 'function')) return;
var id = 'spend-' + Date.now();
window.addEventListener('appmint:sms', function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
window.removeEventListener('appmint:sms', handler);
if (e.detail.status === 'failed') { showMessage('Cannot read SMS: ' + e.detail.reason); return; }
var total = 0;
e.detail.messages.forEach(function (m) {
if (!/debited/i.test(m.body)) return;
var amount = m.body.match(/(?:Rs\.?|INR)\s*([\d,]+(?:\.\d{1,2})?)/i);
if (amount) total += parseFloat(amount[1].replace(/,/g, ''));
});
document.getElementById('spent').textContent = 'Spent: Rs ' + total.toFixed(2);
});
WebToApk.listSms(id, 'inbox', 200, 0);
}Note: limit Ăš limitato a 1-500. Qualsiasi nome di cartella sconosciuto legge la posta in arrivo. Valori di reason: not_enabled, permission_denied, foreign_origin. I messaggi ricevuti raggiungono comunque anche la normale app SMS dell'utente. SMS Ăš un'autorizzazione con restrizioni di Google Play: devi presentare in Play Console una Dichiarazione sulle autorizzazioni approvata (di solito si qualificano solo le app SMS predefinite), altrimenti l'app viene rifiutata.
makePhoneCall bridge#
window.WebToApk.makePhoneCall(phoneNumber: String)
Chiama [phoneNumber]. - Autorizzazione Telefono ATTIVA nella build: avvia direttamente la chiamata. La prima volta, Android chiede all'utente l'autorizzazione Telefono; se la rifiuta, si apre il tastierino con il numero giĂ inserito cosĂŹ puĂČ comunque chiamare da sĂ©. - Autorizzazione Telefono DISATTIVATA: apre il tastierino con il numero inserito (il tastierino non richiede autorizzazioni) e l'utente tocca Chiama. - Una pagina che non Ăš dell'app (un sito esterno aperto nell'app) ottiene sempre il tastierino, mai una chiamata diretta. Un semplice link `tel:` nel tuo HTML apre comunque il tastierino ed Ăš spesso sufficiente.
Esempio
Avvia una chiamata a un numero, oppure apre il tastierino con il numero giĂ inserito.
Restituisce: niente. Richiede: niente per aprire il tastierino. Attiva Telefono nel Passaggio 4 (Accesso) durante la creazione se la chiamata deve partire direttamente.
Un pulsante "Chiama il negozio".
document.getElementById('callShop').addEventListener('click', function () {
if (window.WebToApk && window.WebToApk.makePhoneCall) {
WebToApk.makePhoneCall('+911234567890');
}
});Nessun interruttore necessario: un semplice link tel: apre il tastierino con il numero, nell'app e in un browser. Spesso Ăš tutto ciĂČ che serve.
<a href="tel:+911234567890">Call the shop</a>Un unico gestore per un intero elenco del personale, dove ogni riga porta il suo numero in un attributo data-phone:
document.getElementById('staffList').addEventListener('click', function (e) {
var btn = e.target.closest('[data-phone]');
if (!btn) return;
var number = btn.getAttribute('data-phone').replace(/[^\d+]/g, ''); // keep digits and +
if (!number) return;
if (window.WebToApk && typeof window.WebToApk.makePhoneCall === 'function') {
WebToApk.makePhoneCall(number);
} else {
location.href = 'tel:' + number; // a normal browser
}
});Note: Con Telefono disattivato, il tastierino si apre con il numero e l'utente preme chiama. Con Telefono attivo, la chiamata parte direttamente; la prima volta Android chiede all'utente l'autorizzazione per le chiamate e, se la rifiuta, si apre invece il tastierino cosĂŹ puĂČ comunque chiamare. Una pagina che non Ăš dell'app (un sito esterno aperto nell'app) ottiene sempre il tastierino. Passa il numero come semplice stringa. Non viene riportato nulla: non puoi sapere se la chiamata Ăš partita. L'interruttore Telefono aggiunge l'autorizzazione CALL_PHONE alla tua scheda su Play; dichiarala nel modulo Sicurezza dei dati e attivalo solo se ti serve.
sendSms bridge#
window.WebToApk.sendSms(
WebToApk.composeSms(number, message) <- NESSUNA autorizzazione, apre l'app SMS WebToApk.sendSms(id, number, message, wantDelivery) WebToApk.listSms(id, "inbox"|"sent"|"draft", limit, offset) Risultati dell'invio: `appmint:sms` / window.onAppMintSms {requestId, status:"sent"|"delivered"|"failed", ok, reason?} Messaggi in arrivo: `appmint:sms-received` / window.onAppMintSmsReceived.
Descritta dal suo gruppo, SMS, e non singolarmente.
Esempio
Invia un SMS direttamente dall'app, senza aprire l'app SMS, e riporta cosa Ăš successo davvero.
Restituisce: per ora niente. La risposta Ăš l'evento appmint:sms (e window.onAppMintSms) con detail = { requestId, status: 'sent' | 'delivered' | 'failed', ok, reason? }. Con un rapporto di consegna ricevi DUE risposte in caso di successo: sent, poi delivered. Richiede: attiva SMS (lettura e invio) nel Passaggio 4 (Accesso) durante la creazione; all'utente viene chiesta l'autorizzazione alla prima chiamata.
Invia un codice e segui il suo stato. Non rimuovere il listener dopo la prima risposta quando hai chiesto un rapporto di consegna.
function sendCode(phone, code) {
if (!(window.WebToApk && window.WebToApk.sendSms)) {
showMessage('Sending SMS works only inside the app.');
return;
}
var id = 'sms-' + Date.now();
function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
var d = e.detail;
if (d.status === 'sent' && d.reason === 'no_delivery_report') {
showStatus('Sent (the network gave no delivery report)');
window.removeEventListener('appmint:sms', handler);
} else if (d.status === 'sent') {
showStatus('Sent');
} else if (d.status === 'delivered') {
showStatus('Delivered');
window.removeEventListener('appmint:sms', handler);
} else { // 'failed'
showStatus('Failed: ' + d.reason);
window.removeEventListener('appmint:sms', handler);
}
}
window.addEventListener('appmint:sms', handler);
WebToApk.sendSms(id, phone, 'Your code is ' + code, true); // true = delivery report
}Nessun rapporto di consegna. Passa false come ultimo valore: ricevi esattamente una risposta, sent oppure failed.
window.onAppMintSms = function (d) {
if (d.requestId === 'alert-1') showStatus(d.ok ? 'Alert sent' : 'Failed: ' + d.reason);
};
if (window.WebToApk && window.WebToApk.sendSms) {
WebToApk.sendSms('alert-1', '+911234567890', 'Gate opened at ' + new Date().toLocaleTimeString(), false);
}Lo stesso avviso a un breve elenco di numeri, uno dopo l'altro, raccogliendo ogni risultato (e fermandosi quando gli SMS sono disattivati o rifiutati, perché ogni altro numero fallirebbe allo stesso modo):
function sendToAll(numbers, text, done) {
if (!(window.WebToApk && typeof window.WebToApk.sendSms === 'function')) { done(null); return; }
var results = [], i = 0;
function next() {
if (i >= numbers.length) { done(results); return; }
var number = numbers[i++];
var id = 'notice-' + Date.now() + '-' + i;
window.addEventListener('appmint:sms', function handler(e) {
if (!e.detail || e.detail.requestId !== id) return;
window.removeEventListener('appmint:sms', handler);
results.push({ number: number, ok: e.detail.ok, reason: e.detail.reason });
var r = e.detail.reason;
if (r === 'not_enabled' || r === 'permission_denied' || r === 'foreign_origin') done(results);
else next();
});
WebToApk.sendSms(id, number, text, false); // one answer per number
}
next();
}
sendToAll(['+911234567890', '+919876543210'], 'Practice moved to 6 pm today.', function (results) {
if (!results) return showMessage('Sending SMS works only inside the app.');
showStatus(results.filter(function (r) { return r.ok; }).length + ' of ' + results.length + ' sent');
});Note: Un testo lungo viene diviso in parti e inviato come un unico messaggio. Se entro 60 secondi non arriva alcun rapporto di consegna ricevi status: 'sent' con reason: 'no_delivery_report': il messaggio Ăš stato comunque inviato. Valori di reason: not_enabled, permission_denied, foreign_origin, invalid_arguments (numero o testo vuoto), no_service, radio_off, generic_failure, null_pdu, not_delivered e altri. Usa una stringa per requestId. Ogni SMS puĂČ costare denaro all'utente. SMS Ăš un'autorizzazione con restrizioni di Google Play: devi presentare in Play Console una Dichiarazione sulle autorizzazioni approvata (di solito si qualificano solo le app SMS predefinite), quindi preferisci composeSms quando l'utente puĂČ premere invio.