API del bridge JavaScript
Accesso e passkey
Un vero selettore di account Google, nativo anziché con reindirizzamento web, e passkey tramite il Credential Manager di Android: navigator.credentials funziona come in Chrome, oppure usa AppMint.passkey con le opzioni JSON del tuo server.
AppMint.passkey helper#
window.AppMint.passkey — create(options), get(options), isAvailable(), origin(), assetLinks()
Esempio
Passkey (accedi con impronta, volto o blocco schermo, senza password) tramite il gestore passkey di Android, usando le opzioni JSON create dal tuo server di passkey.
Restituisce: create(optionsJSON) → Promise di RegistrationResponseJSON; get(optionsJSON) → Promise di AuthenticationResponseJSON (invia l'uno o l'altro al tuo server per verificarlo). Entrambi vengono rifiutati con un DOMException (err.name, e err.reason = un breve codice). isAvailable() → booleano, origin() → stringa, assetLinks() → array - tutti subito. Richiede: Android 9+ con Google Play services, un server di passkey e i due passaggi di configurazione qui sotto. Nessun interruttore di build.
Accedi:
async function signInWithPasskey() {
if (!window.AppMint || !window.AppMint.passkey || !window.AppMint.passkey.isAvailable()) {
alert('Passkeys are not available on this phone.');
return;
}
var options = await (await fetch('https://your-domain.com/passkey/login-options')).json();
var answer;
try {
answer = await window.AppMint.passkey.get(options); // rpId must be your domain
} catch (err) {
if (err.name === 'NotAllowedError') return; // cancelled, or no passkey on this phone
alert('Passkey problem: ' + err.message);
return;
}
var res = await fetch('https://your-domain.com/passkey/login-verify', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(answer)
});
if (res.ok) showAccount();
}Creane uno (dopo che l'utente ha effettuato l'accesso in un altro modo):
async function addPasskey() {
var options = await (await fetch('https://your-domain.com/passkey/register-options')).json();
try {
var answer = await window.AppMint.passkey.create(options);
await fetch('https://your-domain.com/passkey/register-verify', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(answer)
});
} catch (err) {
if (err.name === 'InvalidStateError') alert('You already have a passkey here.');
else if (err.name !== 'NotAllowedError') alert('Passkey problem: ' + err.message);
}
}Da fare una sola volta: esegui questo nell'app installata DA Google Play (Play firma con la propria chiave):
console.log(JSON.stringify(window.AppMint.passkey.assetLinks(), null, 2));
// save as https://your-domain.com/.well-known/assetlinks.json
console.log(window.AppMint.passkey.origin());
// android:apk-key-hash:... — add to your server's expected originsNote: err.name / err.reason: NotAllowedError (cancelled, no_credential, interrupted), InvalidStateError (esiste già), SecurityError con not_linked (assetlinks.json non elenca l'app) oppure rp_mismatch (il rpId non è il dominio di questa pagina), NotSupportedError / unavailable (Android < 9 o senza Play services), TypeError / invalid_options (una pagina inclusa nell'app non ha un dominio, quindi imposta rp.id / rpId sul tuo dominio). window.AppMint.passkey esiste solo nell'app; in un browser usa navigator.credentials (lo stesso codice funziona anche nell'app).
WebToApkAuth.signInWithGoogle helper#
window.WebToApkAuth.signInWithGoogle(webClientId)
Esempio
Fa accedere l'utente con il suo account Google tramite il selettore di account di Android e ti restituisce un ID token Google. Google blocca la sua pagina di accesso nelle WebView delle app («disallowed_useragent»); questo percorso nativo non è bloccato.
Restituisce: una Promise di {ok:true, idToken, email, displayName, profilePictureUri}. Viene RIFIUTATA con un Error il cui message è il codice (cancelled, google_play_services_unavailable, missing_web_client_id, failed, …). Richiede: il tuo Web client ID OAuth (termina con .apps.googleusercontent.com) e le impronte SHA-1 e SHA-256 dell'app registrate nel tuo progetto Google / Firebase (dal file _signkey_info.txt della tua build e, se pubblichi su Play, la chiave di firma dell'app di Play). Nessun interruttore di build.
Con Firebase Authentication (SDK compat):
var WEB_CLIENT_ID = '1234567890-abc.apps.googleusercontent.com';
document.getElementById('google-button').addEventListener('click', async function () {
if (!window.WebToApkAuth) {
alert('Google sign-in works in the app.'); // or run your normal web sign-in here
return;
}
try {
var r = await window.WebToApkAuth.signInWithGoogle(WEB_CLIENT_ID);
var cred = firebase.auth.GoogleAuthProvider.credential(r.idToken);
await firebase.auth().signInWithCredential(cred);
showWelcome(r.displayName || r.email);
} catch (err) {
if (err.message === 'cancelled') return; // user closed the picker
if (err.message === 'google_play_services_unavailable') {
alert('No Google account or Google Play services on this phone.');
return;
}
alert('Google sign-in failed: ' + err.message);
}
});Con un tuo server: invia l'ID token e verificalo lì (non fidarti mai di esso solo nella pagina):
async function signInWithMyServer() {
var r = await window.WebToApkAuth.signInWithGoogle(WEB_CLIENT_ID);
await fetch('https://your-domain.com/auth/google', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ idToken: r.idToken })
});
}Con Supabase Auth (passa l'ID token a signInWithIdToken):
async function signInWithSupabase() {
if (!window.WebToApkAuth) {
return supabase.auth.signInWithOAuth({ provider: 'google' }); // normal web sign-in in a browser
}
try {
var r = await window.WebToApkAuth.signInWithGoogle(WEB_CLIENT_ID);
var res = await supabase.auth.signInWithIdToken({ provider: 'google', token: r.idToken });
if (res.error) throw res.error;
showWelcome(res.data.user.email);
} catch (err) {
if (err.message !== 'cancelled') alert('Google sign-in failed: ' + err.message);
}
}Note: Passa il Web client ID. Senza argomento l'helper usa window.firebaseConfig._googleWebClientId se la tua pagina lo imposta, poi il client Web nel google-services.json che hai caricato per questa app (solo quando quel file è il tuo progetto Firebase con l'accesso Google attivo, mai una build AppMint Push); senza nessuno di questi viene rifiutato con missing_web_client_id. Una pagina che non appartiene all'app (un sito esterno aperto nell'app) viene rifiutata con foreign_origin. Usa il Web client ID, non un client ID Android. «No credentials available» di solito significa che lo SHA-1 non è registrato. Questo helper esiste solo nell'app: in un browser usa il tuo normale accesso web. Chiamalo da un tocco su un pulsante.
WebToApkAuth.signOutGoogle helper#
window.WebToApkAuth.signOutGoogle()
Esempio
Cancella la scelta di accesso Google salvata da Android, così il prossimo signInWithGoogle mostra di nuovo il selettore di account invece di riutilizzare in silenzio l'ultimo account.
Restituisce: una Promise di {ok:true}; viene rifiutata con un Error il cui message dice che cosa è andato storto. Richiede: nulla.
Chiamalo insieme alla tua disconnessione:
document.getElementById('sign-out').addEventListener('click', async function () {
await firebase.auth().signOut(); // your normal sign-out (Firebase here)
if (window.WebToApkAuth) {
try {
await window.WebToApkAuth.signOutGoogle();
} catch (err) {
console.log('Could not clear the Google choice: ' + err.message);
}
}
showSignInScreen();
});Un pulsante «Cambia account»: cancella la scelta salvata, poi accedi di nuovo così l'utente sceglie un altro account:
async function switchGoogleAccount() {
if (!window.WebToApkAuth) return;
await firebase.auth().signOut();
try { await window.WebToApkAuth.signOutGoogle(); } catch (err) { /* nothing saved to clear */ }
try {
var r = await window.WebToApkAuth.signInWithGoogle('1234567890-abc.apps.googleusercontent.com');
await firebase.auth().signInWithCredential(firebase.auth.GoogleAuthProvider.credential(r.idToken));
} catch (err) {
if (err.message !== 'cancelled') alert('Google sign-in failed: ' + err.message);
showSignInScreen();
}
}Prima disconnettiti dal tuo server, poi cancella la scelta Google senza lasciare che un errore blocchi la disconnessione:
async function signOutEverywhere() {
await fetch('https://your-domain.com/auth/logout', { method: 'POST', credentials: 'include' });
localStorage.removeItem('profile');
if (window.WebToApkAuth) {
var r = await window.WebToApkAuth.signOutGoogle()
.catch(function (err) { return { ok: false, error: err.message }; });
if (!r.ok) console.log('Google choice not cleared: ' + r.error);
}
location.replace('/login');
}Note: Questo non termina la sessione della tua app: disconnetti tu l'utente dal tuo backend. Reimposta solo quale account Google il telefono propone la volta successiva.
OTPCredential standard web#
navigator.credentials.get({ otp: { transport: ['sms'] } }) — WebOTP
Esempio
L'API standard WebOTP: il codice di accesso ricevuto via SMS si compila da solo. Android mostra la schermata di Google «Consentire a questa app di leggere questo messaggio?»: nessuna autorizzazione SMS.
Restituisce: una Promise di un OTPCredential {type:'otp', code}. Viene rifiutata con AbortError quando l'utente tocca Nega o il segnale annulla, con InvalidStateError dopo cinque minuti senza SMS, con NotSupportedError senza Google Play services. Richiede: nulla da attivare. L'SMS deve TERMINARE con una riga che indica l'host di questa pagina: @<host> #<code>.
const input = document.querySelector('input[autocomplete="one-time-code"]');
if ('OTPCredential' in window) {
const ac = new AbortController();
document.querySelector('form').addEventListener('submit', () => ac.abort());
navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal })
.then((otp) => { input.value = otp.code; input.form.requestSubmit(); })
.catch((e) => console.log('Type the code instead:', e.name));
}L'SMS che invia il tuo server (l'ultima riga è il vincolo):
Your Acme code is 482913.
@acme.example #482913Dopo «Invia di nuovo il codice», avvia una nuova richiesta (sostituisce quella ancora in attesa, che viene rifiutata con AbortError):
async function resendAndWait(phone) {
await fetch('/api/send-code', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone })
});
if (!('OTPCredential' in window)) return;
try {
const otp = await navigator.credentials.get({ otp: { transport: ['sms'] } });
await verifyCode(otp.code);
} catch (e) {
if (e.name === 'InvalidStateError') showMessage('No SMS yet. Tap Resend to try again.');
}
}Note: l'host deve essere l'host della pagina stessa: per un'app basata su sito web è il tuo dominio (l'SMS che Chrome già legge); per un'app offline/creata con l'AI è appassets.androidplatform.net. Un messaggio per un altro host viene ignorato e l'app continua ad attendere. Solo pagina principale (i codici legati a un'origine incorporata, @top #code @iframe, non sono supportati). Solo una richiesta alla volta è in attesa; una più recente annulla la precedente. Evento che ne deriva: appmint:otp.
__otpCancel bridge#
window.WebToApk.__otpCancel(requestId: String)
Abbandona una richiesta WebOTP in sospeso (AbortSignal, o una richiesta più recente l'ha sostituita).
Esempio
Trasporto interno dietro l'annullamento di una richiesta WebOTP (AbortSignal). Le pagine usano l'API standard; non chiamare mai questo direttamente: i metodi __ possono cambiare senza preavviso.
Restituisce: niente. Richiede: nulla da attivare.
Usa l'API pubblica:
const ac = new AbortController();
const cred = await navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal });
codeInput.value = cred.code;
ac.abort(); // the pending get() rejects with AbortErrorSmetti di attendere non appena l'utente inizia a digitare il codice da solo:
const input = document.querySelector('input[autocomplete="one-time-code"]');
const ac = new AbortController();
input.addEventListener('input', () => ac.abort(), { once: true });
navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal })
.then((cred) => { input.value = cred.code; })
.catch((e) => { if (e.name !== 'AbortError') console.log('No code:', e.name); });Annulla l'attesa quando l'utente torna indietro per cambiare il numero di telefono:
let otpAbort = null;
function waitForSms() {
otpAbort = new AbortController();
return navigator.credentials.get({ otp: { transport: ['sms'] }, signal: otpAbort.signal });
}
document.getElementById('change-number').addEventListener('click', () => {
if (otpAbort) { otpAbort.abort(); otpAbort = null; } // the pending get() rejects with AbortError
showPhoneStep();
});Note: Implementato nella shell dell'app (WebApiPolyfills.kt). Lo stesso codice della pagina funziona senza modifiche in Chrome.
__otpStart bridge#
window.WebToApk.__otpStart(requestId: String)
WebOTP: attende (fino a cinque minuti) un SMS tramite la schermata SMS User Consent di Google, senza autorizzazione SMS. La risposta è `appmint:otp {requestId, message|error}`.
Esempio
Trasporto interno dietro navigator.credentials.get({ otp: { transport: ['sms'] } }). Le pagine usano l'API standard; non chiamare mai questo direttamente: i metodi __ possono cambiare senza preavviso.
Restituisce: niente; la risposta arriva come evento appmint:otp {requestId, message} oppure {requestId, error} (cancelled, timeout, unavailable). Richiede: nulla da attivare.
Usa l'API pubblica:
const ac = new AbortController();
const cred = await navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal });
codeInput.value = cred.code;Smetti di attendere dopo un minuto con un segnale di timeout:
async function waitForCode(input) {
if (!('OTPCredential' in window)) return;
try {
const cred = await navigator.credentials.get({
otp: { transport: ['sms'] },
signal: AbortSignal.timeout(60000)
});
input.value = cred.code;
} catch (e) {
// TimeoutError after 60 s, AbortError when the user taps Deny
showMessage('Type the code from the SMS.');
}
}Dì all'utente cosa fare dopo, in base al nome dell'errore:
async function readOtp() {
try {
const cred = await navigator.credentials.get({ otp: { transport: ['sms'] } });
return cred.code;
} catch (e) {
if (e.name === 'InvalidStateError') showResendButton(); // no SMS within five minutes
else if (e.name === 'NotSupportedError') showManualEntry(); // no Google Play services
return null; // AbortError: the user tapped Deny
}
}Note: Implementato nella shell dell'app (WebApiPolyfills.kt). Lo stesso codice della pagina funziona senza modifiche in Chrome.
passkeyAssetLinks bridge#
window.WebToApk.passkeyAssetLinks(): String
L'array assetlinks.json (come testo) che autorizza questa app installata per il tuo dominio.
Esempio
Crea il contenuto di assetlinks.json che indica ad Android che il tuo dominio si fida di questa app (nome del pacchetto + SHA-256 del certificato con cui è firmata l'app installata). Le pagine di solito usano l'API pubblica AppMint.passkey.assetLinks(), che incapsula questa chiamata e restituisce un array già analizzato.
Restituisce: un array JSON come TESTO, subito ("[]" se il certificato non può essere letto). Richiede: nulla.
Eseguilo una volta nell'app installata DA Google Play, poi salva l'output come https://your-domain.com/.well-known/assetlinks.json:
if (window.AppMint && window.AppMint.passkey) {
console.log(JSON.stringify(window.AppMint.passkey.assetLinks(), null, 2));
}La chiamata grezza restituisce il testo già formattato:
if (window.WebToApk && typeof window.WebToApk.passkeyAssetLinks === 'function') {
var text = window.WebToApk.passkeyAssetLinks();
console.log(text);
}Leggi il nome del pacchetto e l'impronta SHA-256 dalla dichiarazione, per una console che li richiede uno alla volta:
if (window.AppMint && window.AppMint.passkey) {
var statements = window.AppMint.passkey.assetLinks();
if (statements.length === 0) {
console.log('The signing certificate could not be read.');
} else {
var target = statements[0].target;
console.log('Package: ' + target.package_name);
console.log('SHA-256: ' + target.sha256_cert_fingerprints[0]); // AB:CD:... upper-case, colon-separated
}
}Note: il dominio deve essere esattamente l'rpID del tuo server (www. è un dominio diverso), servito in https senza reindirizzamenti. Se il file è sbagliato, le chiamate alle passkey falliscono con SecurityError (motivo not_linked).
passkeyIsAvailable bridge#
window.WebToApk.passkeyIsAvailable(): Boolean
True su Android 9+ con Google Play services: i telefoni che possono contenere una passkey.
Esempio
Ti dice se questo telefono può usare le passkey. Le pagine di solito usano l'API pubblica AppMint.passkey.isAvailable() (oppure PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()), che incapsula questa chiamata.
Restituisce: un booleano, subito - true su Android 9+ con Google Play services e una WebView abbastanza recente per il canale passkey. Richiede: nulla.
L'API pubblica:
var canPasskey = !!(window.AppMint && window.AppMint.passkey && window.AppMint.passkey.isAvailable());
document.getElementById('passkey-button').hidden = !canPasskey;La chiamata diretta, se ti serve:
var canPasskey = !!window.WebToApk &&
typeof window.WebToApk.passkeyIsAvailable === 'function' &&
window.WebToApk.passkeyIsAvailable() === true;Proponi «Aggiungi una passkey» una sola volta dopo un accesso con password, solo sui telefoni che possono contenerne una (il controllo standard, stesso codice in Chrome):
async function offerPasskeyAfterLogin() {
var ok = !!window.PublicKeyCredential &&
await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
if (!ok) return; // Android below 9 or no Google Play services
if (localStorage.getItem('passkey-offered')) return;
localStorage.setItem('passkey-offered', '1');
document.getElementById('add-passkey-banner').hidden = false;
}Note: Quando è false, AppMint.passkey.create/get vengono rifiutate con NotSupportedError. Nascondi il pulsante della passkey e offri il tuo altro metodo di accesso.
passkeyOrigin bridge#
window.WebToApk.passkeyOrigin(): String
L'origine che un server di passkey vede da questa app: `android:apk-key-hash:<base64url SHA-256>`.
Esempio
Fornisce l'origine che il tuo server di passkey vede da questa app: android:apk-key-hash:<base64url SHA-256 of the signing certificate>. Le pagine di solito usano l'API pubblica AppMint.passkey.origin(), che incapsula questa chiamata.
Restituisce: una stringa, subito ("" se il certificato non può essere letto). Richiede: nulla.
Eseguilo una volta nell'app installata DA Google Play e aggiungi il valore alle origini consentite del tuo server:
if (window.AppMint && window.AppMint.passkey) {
console.log(window.AppMint.passkey.origin()); // android:apk-key-hash:Lir5oIjf552K...
}La chiamata diretta restituisce la stessa stringa:
if (window.WebToApk && typeof window.WebToApk.passkeyOrigin === 'function') {
console.log(window.WebToApk.passkeyOrigin());
}Mostra l'origine in una schermata delle impostazioni nascosta, così puoi leggerla dall'installazione da Play senza un debugger:
var out = document.getElementById('passkey-origin');
var origin = (window.AppMint && window.AppMint.passkey) ? window.AppMint.passkey.origin() : '';
if (!origin) {
out.textContent = 'Open this screen in the installed app.';
} else {
out.textContent = origin; // android:apk-key-hash:...
out.style.userSelect = 'all'; // one long-press selects the whole value
}Note: Google Play ri-firma la tua app, quindi un APK di prova dà un valore diverso dall'installazione da Play. Esempio con SimpleWebAuthn: expectedOrigin: ['https://your-domain.com', 'android:apk-key-hash:...'].
signInWithGoogle bridge#
window.WebToApk.signInWithGoogle(serverClientId: String, callbackId: String)
===== Accesso Google nativo tramite Credential Manager ===== Aggira il blocco OAuth di Google nelle WebView Android (errore disallowed_useragent) eseguendo il flusso di accesso in Android nativo e riportando a JS solo il token ID Google risultante, dove l'SDK Web di Firebase lo usa tramite GoogleAuthProvider.credential(idToken) + signInWithCredential(...). Contratto JS: window.WebToApk.signInWithGoogle(serverClientId, callbackId) serverClientId "" = il client Web (type 3) nel google-services.json del creatore per questo pacchetto; se non ce n'è, errore "missing_web_client_id". Una pagina che non appartiene all'app riceve l'errore "foreign_origin". -> al termine, viene chiamato window.__webToApkAuth[callbackId](resultJsonString) resultJsonString = '{"ok":true,"idToken":"...","email":"...","displayName":"..."}' oppure '{"ok":false,"error":"<message>"}'
Esempio
Avvia l'accesso Google nativo (il selettore di account di Android) e risponde con un ID token Google. Le pagine di solito usano l'helper Promise WebToApkAuth.signInWithGoogle(webClientId), che incapsula questa chiamata.
Restituisce: niente. La risposta arriva dopo: la shell chiama window.__webToApkAuth[callbackId](json) con '{"ok":true,"idToken":"...","email":"...","displayName":"...","profilePictureUri":"..."}' oppure '{"ok":false,"error":"<code>","detail":"..."}', poi rimuove quella voce. Richiede: il tuo OAuth Web client ID e gli SHA-1 / SHA-256 dell'app registrati nel tuo progetto Google o Firebase. Nessun interruttore di build.
L'helper (consigliato):
async function googleSignIn() {
if (!window.WebToApkAuth) return null;
try {
var r = await window.WebToApkAuth.signInWithGoogle('1234567890-abc.apps.googleusercontent.com');
return r.idToken;
} catch (err) {
if (err.message !== 'cancelled') alert('Google sign-in failed: ' + err.message);
return null;
}
}La chiamata grezza (ordine degli argomenti: web client ID, poi l'id della tua callback):
function googleSignInRaw(done) {
if (!window.WebToApk || typeof window.WebToApk.signInWithGoogle !== 'function') return;
var id = 'g_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) {
var r = JSON.parse(json);
if (r.ok) done(r.idToken, r.email);
else if (r.error !== 'cancelled') alert('Google sign-in failed: ' + r.error);
};
window.WebToApk.signInWithGoogle('1234567890-abc.apps.googleusercontent.com', id);
}La chiamata grezza con un client ID vuoto, che usa il client Web del google-services.json che hai caricato:
function googleSignInFromUploadedFile() {
return new Promise(function (resolve, reject) {
if (!window.WebToApk || typeof window.WebToApk.signInWithGoogle !== 'function') {
return reject(new Error('not_in_app'));
}
var id = 'g_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) {
var r = JSON.parse(json);
if (r.ok) resolve(r); else reject(new Error(r.error));
};
window.WebToApk.signInWithGoogle('', id);
});
}
googleSignInFromUploadedFile()
.then(function (r) { showProfile(r.displayName, r.profilePictureUri); })
.catch(function (e) {
if (e.message === 'missing_web_client_id') console.log('Pass your Web client ID: the uploaded file has none.');
});Note: Codici di errore: cancelled (l'utente ha chiuso il selettore), google_play_services_unavailable (nessun account Google o provider - è anche l'aspetto di una registrazione SHA-1 mancante), missing_web_client_id (non ne è stato passato nessuno e non c'è un client Web nel google-services.json che hai caricato), foreign_origin (la pagina visualizzata non appartiene all'app), failed, unexpected_credential_type, parse_failed: .... Un primo argomento vuoto usa il client Web del tuo google-services.json caricato, se ne ha uno. Verifica l'ID token sul tuo server (oppure passalo a Firebase con GoogleAuthProvider.credential(idToken)).
signOutGoogle bridge#
window.WebToApk.signOutGoogle(callbackId: String)
Cancella lo stato salvato di Credential Manager, così la prossima chiamata a signInWithGoogle mostra di nuovo il selettore di account (invece di riselezionare in silenzio l'ultimo account). Le app generate dovrebbero chiamarlo alla disconnessione avviata dall'utente, oltre a firebase.auth().signOut().
Esempio
Cancella lo stato di accesso Google salvato da Android, così al prossimo accesso viene mostrato di nuovo il selettore di account. Le pagine di solito usano l'helper Promise WebToApkAuth.signOutGoogle(), che incapsula questa chiamata.
Restituisce: niente. La risposta arriva dopo: la shell chiama window.__webToApkAuth[callbackId](json) con '{"ok":true}' oppure '{"ok":false,"error":"..."}'. Richiede: nulla.
L'helper (consigliato):
async function signOut() {
await myBackendSignOut(); // end your own session first
if (window.WebToApkAuth) {
try { await window.WebToApkAuth.signOutGoogle(); } catch (err) { /* nothing to undo */ }
}
}La chiamata grezza:
if (window.WebToApk && typeof window.WebToApk.signOutGoogle === 'function') {
var id = 'gout_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) {
var r = JSON.parse(json);
if (!r.ok) console.log('Google sign-out failed: ' + r.error);
};
window.WebToApk.signOutGoogle(id);
}La chiamata grezza incapsulata in una Promise, usata quando l'utente elimina il proprio account:
function clearGoogleChoice() {
return new Promise(function (resolve) {
if (!window.WebToApk || typeof window.WebToApk.signOutGoogle !== 'function') return resolve(false);
var id = 'gout_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json).ok === true); };
window.WebToApk.signOutGoogle(id);
});
}
async function deleteAccount() {
await fetch('https://your-domain.com/account', { method: 'DELETE', credentials: 'include' });
await clearGoogleChoice(); // the next sign-in starts from the account picker
showSignInScreen();
}Note: Non disconnette l'utente da Firebase né dal tuo server: fallo tu.