Ücretsiz APK oluştur

JavaScript köprü API'si

Giriş ve parola anahtarları

Web yönlendirmesi yerine yerel, gerçek bir Google hesap seçici ve Android'in Credential Manager'ı üzerinden geçiş anahtarları - navigator.credentials Chrome'daki gibi çalışır veya sunucunuzun JSON seçenekleriyle AppMint.passkey kullanın.

AppMint.passkey yardımcı#

window.AppMint.passkey — create(options), get(options), isAvailable(), origin(), assetLinks()

Örnek

Android'in geçiş anahtarı yöneticisi aracılığıyla, geçiş anahtarı sunucunuzun ürettiği JSON seçeneklerini kullanarak geçiş anahtarları (parmak izi, yüz veya ekran kilidiyle - parolasız - oturum açma).

Döndürür: create(optionsJSON) → RegistrationResponseJSON Promise'i; get(optionsJSON) → AuthenticationResponseJSON Promise'i (doğrulamak için ikisini de sunucunuza gönderin). İkisi de bir DOMException ile reddedilir (err.name ve err.reason = kısa bir kod). isAvailable() → boolean, origin() → metin, assetLinks() → dizi - hepsi hemen. Gerektirir: Google Play hizmetleriyle Android 9+, bir geçiş anahtarı sunucusu ve aşağıdaki iki kurulum adımı. Derleme anahtarı yok.

Oturum açın:

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();
}

Bir tane oluşturun (kullanıcı başka bir yolla giriş yaptıktan sonra):

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);
  }
}

Bir kez kurun - bunu Google Play'den yüklenen uygulamada çalıştırın (Play kendi anahtarıyla imzalar):

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 origins

Notlar: err.name / err.reason: NotAllowedError (cancelled, no_credential, interrupted), InvalidStateError (zaten var), SecurityError ile not_linked (assetlinks.json uygulamayı listelemiyor) veya rp_mismatch (rpId bu sayfanın alan adı değil), NotSupportedError / unavailable (Android < 9 veya Play hizmetleri yok), TypeError / invalid_options (uygulamaya gömülü bir sayfanın kendi alan adı yoktur, bu yüzden rp.id / rpId değerini alan adınıza ayarlayın). window.AppMint.passkey yalnızca uygulamada bulunur; tarayıcıda navigator.credentials kullanın (aynı kod uygulamada da çalışır).

WebToApkAuth.signInWithGoogle yardımcı#

window.WebToApkAuth.signInWithGoogle(webClientId)

Örnek

Kullanıcıyı Android'in kendi hesap seçicisi üzerinden Google hesabıyla oturum açtırır ve size bir Google ID belirteci verir. Google, uygulama WebView'larında oturum açma sayfasını engeller ("disallowed_useragent"); bu yerel yol engellenmez.

Döndürür: {ok:true, idToken, email, displayName, profilePictureUri} değerinin bir Promise'i. Error ile REDDEDİLİR; message kod olur (cancelled, google_play_services_unavailable, missing_web_client_id, failed, …). Gerektirir: OAuth Web istemci kimliğiniz (.apps.googleusercontent.com ile biter) ve uygulamanın SHA-1 ve SHA-256 parmak izlerinin Google / Firebase projenize kayıtlı olması (derlemenizin _signkey_info.txt dosyasından ve Play'de yayınlıyorsanız Play'in uygulama imzalama anahtarından). Derleme anahtarı yok.

Firebase Authentication ile (compat SDK):

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);
  }
});

Kendi sunucunuzla - ID belirtecini gönderin ve orada doğrulayın (asla yalnızca sayfada güvenmeyin):

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 })
  });
}

Supabase Auth ile (ID belirtecini şuna verin: 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);
  }
}

Notlar: Web istemci kimliğini verin. Bağımsız değişken yoksa yardımcı, sayfanız ayarladıysa window.firebaseConfig._googleWebClientId değerini, sonra bu uygulama için yüklediğiniz google-services.json içindeki Web istemcisini kullanır (yalnızca o dosya Google ile oturum açmanın etkin olduğu kendi Firebase projenize aitse - asla bir AppMint Push derlemesi değil); bunlardan hiçbiri yoksa missing_web_client_id ile reddeder. Uygulamanın kendisine ait olmayan bir sayfa (uygulamanın içinde açılan harici bir site) foreign_origin ile reddedilir. Android istemci kimliği değil, WEB istemci kimliğini kullanın. "No credentials available" genellikle SHA-1'in kayıtlı olmadığı anlamına gelir. Bu yardımcı yalnızca uygulamada bulunur - tarayıcıda normal web oturum açmanızı kullanın. Bir düğme dokunuşundan çağırın.

WebToApkAuth.signOutGoogle yardımcı#

window.WebToApkAuth.signOutGoogle()

Örnek

Android'in kayıtlı Google oturum açma seçimini temizler, böylece bir sonraki signInWithGoogle son hesabı sessizce yeniden kullanmak yerine hesap seçiciyi yeniden gösterir.

Döndürür: {ok:true} değerinin bir Promise'i; neyin yanlış gittiğini message ile söyleyen bir Error ile reddedilir. Gerektirir: hiçbir şey.

Kendi oturum kapatmanızla birlikte çağırın:

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();
});

Bir "Hesap değiştir" düğmesi: kayıtlı seçimi temizleyin, ardından kullanıcının başka bir hesap seçmesi için tekrar oturum açın:

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();
  }
}

Önce kendi sunucunuzdan çıkış yapın, ardından bir hatanın çıkışı engellemesine izin vermeden Google seçimini temizleyin:

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');
}

Notlar: Bu, uygulamanızın kendi oturumunu kapatmaz - kullanıcının arka ucunuzdaki oturumunu kendiniz kapatın. Yalnızca telefonun bir dahaki sefere hangi Google hesabını sunacağını sıfırlar.

navigator.credentials web standardı#

navigator.credentials.create / get({ publicKey }) — passkeys

Örnek

Standart WebAuthn geçiş anahtarı çağrıları. Normal bir Android WebView bunları yapamaz; uygulamada Android'in geçiş anahtarı yöneticisine gider, böylece Chrome için yazılmış kod ve kütüphaneler (SimpleWebAuthn, Hanko, Corbado, Auth0) değişiklik olmadan çalışır.

Döndürür: Chrome'daki gibi tam olarak bir PublicKeyCredential (.toJSON() ile) Promise'i; bir DOMException ile reddedilir. Gerektirir: Google Play hizmetleriyle Android 9+, bir geçiş anahtarı sunucusu, uygulamayı listeleyen alan adınızın assetlinks.json dosyası ve sunucunuzun uygulamanın kaynağını kabul etmesi (bkz. AppMint.passkey). Derleme anahtarı yok.

Standart API ile oturum açın (seçenekler sunucunuzdan, ikili alanlar ArrayBuffer olarak):

async function signIn() {
  if (!window.PublicKeyCredential) { alert('Passkeys are not supported here.'); return; }
  var ok = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
  if (!ok) { alert('This phone cannot use passkeys.'); return; }

  try {
    var json = await (await fetch('https://your-domain.com/passkey/login-options')).json();
    var publicKey = PublicKeyCredential.parseRequestOptionsFromJSON(json);  // provided in the app too
    var cred = await navigator.credentials.get({ publicKey: publicKey });
    await fetch('https://your-domain.com/passkey/login-verify', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(cred.toJSON())
    });
  } catch (err) {
    if (err.name !== 'NotAllowedError') alert('Passkey problem: ' + err.message);
  }
}

Bir geçiş anahtarı kaydedin:

async function register() {
  if (!window.PublicKeyCredential) return;
  try {
    var json = await (await fetch('https://your-domain.com/passkey/register-options')).json();
    var cred = await navigator.credentials.create({
      publicKey: PublicKeyCredential.parseCreationOptionsFromJSON(json)
    });
    await fetch('https://your-domain.com/passkey/register-verify', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(cred.toJSON())
    });
  } catch (err) {
    if (err.name === 'InvalidStateError') alert('You already have a passkey here.');
    else if (err.name !== 'NotAllowedError') alert('Passkey problem: ' + err.message);
  }
}

Telefonun desteklediklerine göre hangi oturum açma düğmelerinin gösterileceğine karar verin (geçiş anahtarı otomatik doldurma uygulamada kapalıdır, bu yüzden bir düğme bulundurun):

async function setupSignInButtons() {
  if (!window.PublicKeyCredential) return;
  var caps = typeof PublicKeyCredential.getClientCapabilities === 'function'
    ? await PublicKeyCredential.getClientCapabilities() : {};
  var platform = caps.passkeyPlatformAuthenticator ||
    await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
  document.getElementById('passkey-button').hidden = !platform;
  if (caps.conditionalGet) startPasskeyAutofill();   // false in the app; true in some browsers
}

Notlar: Bir metin alanında geçiş anahtarı otomatik doldurma (mediation: 'conditional') uygulamada kullanılamaz - isConditionalMediationAvailable() false yanıtı verir ve çağrı NotSupportedError ile reddedilir; oturum açmayı bir düğmeden başlatın. signal (AbortController) çalışır. Uygulamaya gömülü bir sayfanın kendi alan adı yoktur: rp.id / rpId değerini alan adınıza ayarlayın. publicKey olmayan çağrılar (parolalar, OTP) eskisi gibi WebView'a gider.

OTPCredential web standardı#

navigator.credentials.get({ otp: { transport: ['sms'] } }) — WebOTP

Örnek

Standart WebOTP API'si: bir SMS'teki giriş kodu kendiliğinden doldurulur. Android, Google'ın "Bu uygulamanın bu mesajı okumasına izin verilsin mi?" sayfasını gösterir - SMS izni gerekmez.

Döndürür: bir OTPCredential {type:'otp', code} Promise'i. Kullanıcı Reddet'e dokunduğunda veya sinyal iptal edildiğinde AbortError ile, beş dakika SMS gelmezse InvalidStateError ile, Google Play hizmetleri yoksa NotSupportedError ile reddedilir. Gerektirir: açılacak bir şey yok. SMS, bu sayfanın ana bilgisayarını adlandıran bir satırla BİTMELİDİR: @<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));
}

Sunucunuzun gönderdiği SMS (son satır bağlamadır):

Your Acme code is 482913.

@acme.example #482913

"Kodu yeniden gönder"den sonra yeni bir istek başlatın (hâlâ bekleyen isteğin yerini alır, o da AbortError ile reddedilir):

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.');
  }
}

Notlar: ana bilgisayar sayfanın kendi ana bilgisayarı olmalıdır - web sitesi tabanlı bir uygulama için bu sizin alan adınızdır (Chrome'un zaten okuduğu SMS); çevrimdışı/AI ile oluşturulmuş bir uygulama için appassets.androidplatform.net. Başka bir ana bilgisayara ait mesaj yok sayılır ve uygulama beklemeye devam eder. Yalnızca üst sayfa (gömülü bir kaynağa bağlı kodlar, @top #code @iframe, desteklenmez). Aynı anda yalnızca bir istek bekler; yenisi eskisini iptal eder. Arkasındaki olay: appmint:otp.

__otpCancel köprü#

window.WebToApk.__otpCancel(requestId: String)

Bekleyen bir WebOTP isteğinden vazgeçer (AbortSignal veya yeni bir istek onun yerini aldı).

Örnek

Bir WebOTP isteğini iptal etmenin (AbortSignal) arkasındaki dahili aktarım. Sayfalar standart API'yi kullanır; bunu asla doğrudan çağırmayın - __ yöntemleri haber verilmeden değişebilir.

Döndürür: hiçbir şey. Gerektirir: açılacak bir şey yok.

Genel API'yi kullanın:

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 AbortError

Kullanıcı kodu kendisi yazmaya başlar başlamaz beklemeyi bırakın:

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); });

Kullanıcı telefon numarasını değiştirmek için geri döndüğünde beklemeyi iptal edin:

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();
});

Notlar: Uygulama kabuğunda uygulanmıştır (WebApiPolyfills.kt). Aynı sayfa kodu Chrome'da da değişmeden çalışır.

__otpStart köprü#

window.WebToApk.__otpStart(requestId: String)

WebOTP: Google'ın SMS Kullanıcı Onayı sayfası üzerinden bir SMS için (en fazla beş dakika) bekler - SMS izni gerekmez. Yanıt `appmint:otp {requestId, message|error}` olarak gelir.

Örnek

navigator.credentials.get({ otp: { transport: ['sms'] } }) arkasındaki dahili aktarım. Sayfalar standart API'yi kullanır; bunu asla doğrudan çağırmayın - __ yöntemleri haber verilmeden değişebilir.

Döndürür: hiçbir şey; yanıt appmint:otp olayı {requestId, message} veya {requestId, error} (cancelled, timeout, unavailable) olarak gelir. Gerektirir: açılacak bir şey yok.

Genel API'yi kullanın:

const ac = new AbortController();
const cred = await navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal });
codeInput.value = cred.code;

Zaman aşımı sinyaliyle bir dakika sonra beklemeyi bırakın:

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.');
  }
}

Hata adına göre kullanıcıya sonraki adımda ne yapacağını söyleyin:

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
  }
}

Notlar: Uygulama kabuğunda uygulanmıştır (WebApiPolyfills.kt). Aynı sayfa kodu Chrome'da da değişmeden çalışır.

passkeyIsAvailable köprü#

window.WebToApk.passkeyIsAvailable(): Boolean

Google Play hizmetleriyle Android 9+ üzerinde doğrudur - geçiş anahtarı tutabilen telefonlar.

Örnek

Bu telefonun geçiş anahtarlarını kullanıp kullanamayacağını söyler. Sayfalar normalde bu çağrıyı saran genel API AppMint.passkey.isAvailable() (veya PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()) kullanır.

Döndürür: hemen bir boolean - Google Play hizmetleri olan ve WebView'ı geçiş anahtarı kanalı için yeterince yeni Android 9+ üzerinde true. Gerektirir: hiçbir şey.

Genel API:

var canPasskey = !!(window.AppMint && window.AppMint.passkey && window.AppMint.passkey.isAvailable());
document.getElementById('passkey-button').hidden = !canPasskey;

Gerekirse ham çağrı:

var canPasskey = !!window.WebToApk &&
  typeof window.WebToApk.passkeyIsAvailable === 'function' &&
  window.WebToApk.passkeyIsAvailable() === true;

Bir parola ile oturum açtıktan sonra yalnızca geçiş anahtarı tutabilen telefonlarda bir kez "Geçiş anahtarı ekle" önerin (standart kontrol, Chrome'daki aynı kod):

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;
}

Notlar: Bu false olduğunda, AppMint.passkey.create/get NotSupportedError ile reddedilir. Geçiş anahtarı düğmesini gizleyin ve diğer oturum açma yönteminizi sunun.

passkeyOrigin köprü#

window.WebToApk.passkeyOrigin(): String

Bir parola anahtarı (passkey) sunucusunun bu uygulamadan gördüğü kaynak: `android:apk-key-hash:<base64url SHA-256>`.

Örnek

Geçiş anahtarı sunucunuzun bu uygulamadan gördüğü kaynağı verir: android:apk-key-hash:<base64url SHA-256 of the signing certificate>. Sayfalar normalde bu çağrıyı saran genel API AppMint.passkey.origin() kullanır.

Döndürür: hemen bir metin (sertifika okunamazsa ""). Gerektirir: hiçbir şey.

Bunu Google Play'DEN yüklenen uygulamada bir kez çalıştırın ve değeri sunucunuzun izin verilen kaynaklarına ekleyin:

if (window.AppMint && window.AppMint.passkey) {
  console.log(window.AppMint.passkey.origin());   // android:apk-key-hash:Lir5oIjf552K...
}

Ham çağrı aynı dizeyi verir:

if (window.WebToApk && typeof window.WebToApk.passkeyOrigin === 'function') {
  console.log(window.WebToApk.passkeyOrigin());
}

Kaynağı (origin) gizli bir ayarlar ekranında gösterin; böylece hata ayıklayıcı olmadan Play'den yüklenen uygulamadan okuyabilirsiniz:

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
}

Notlar: Google Play uygulamanızı yeniden imzalar, bu yüzden bir test APK'sı Play kurulumundan farklı bir değer verir. SimpleWebAuthn örneği: expectedOrigin: ['https://your-domain.com', 'android:apk-key-hash:...'].

signInWithGoogle köprü#

window.WebToApk.signInWithGoogle(serverClientId: String, callbackId: String)

===== Credential Manager ile yerel Google ile Oturum Açma ===== Google'ın Android WebView OAuth engelini (disallowed_useragent hatası) aşmak için oturum açma akışını yerel Android'de çalıştırır ve yalnızca ortaya çıkan Google ID belirtecini JS'e geri iletir; orada Firebase Web SDK bunu GoogleAuthProvider.credential(idToken) + signInWithCredential(...) ile kullanır. JS sözleşmesi: window.WebToApk.signInWithGoogle(serverClientId, callbackId) serverClientId "" = bu paket için oluşturucunun kendi google-services.json dosyasındaki Web istemcisi (tür 3); hiçbiri yoksa hata "missing_web_client_id". Uygulamanın kendisine ait olmayan bir sayfa "foreign_origin" hatası alır. -> tamamlandığında window.__webToApkAuth[callbackId](resultJsonString) çağrılır resultJsonString = '{"ok":true,"idToken":"...","email":"...","displayName":"..."}' veya '{"ok":false,"error":"<message>"}'

Örnek

Yerel Google oturum açmayı (Android'in hesap seçicisi) başlatır ve bir Google ID belirteciyle yanıt verir. Sayfalar normalde bu çağrıyı saran WebToApkAuth.signInWithGoogle(webClientId) Promise yardımcısını kullanır.

Döndürür: hiçbir şey. Yanıt sonra gelir: kabuk window.__webToApkAuth[callbackId](json) işlevini '{"ok":true,"idToken":"...","email":"...","displayName":"...","profilePictureUri":"..."}' veya '{"ok":false,"error":"<code>","detail":"..."}' ile çağırır, ardından o girişi kaldırır. Gerektirir: OAuth Web istemci kimliğiniz ve uygulamanın SHA-1 / SHA-256 değerlerinin Google veya Firebase projenize kayıtlı olması. Derleme anahtarı yok.

Yardımcı (önerilen):

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;
  }
}

Ham çağrı (bağımsız değişken sırası: web istemci kimliği, ardından geri çağırma kimliğiniz):

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);
}

Yüklediğiniz google-services.json dosyasındaki Web istemcisini kullanan boş istemci kimlikli ham çağrı:

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.');
  });

Notlar: Hata kodları: cancelled (kullanıcı seçiciyi kapattı), google_play_services_unavailable (Google hesabı veya sağlayıcı yok - eksik SHA-1 kaydı da böyle görünür), missing_web_client_id (hiçbiri verilmedi ve yüklediğiniz google-services.json içinde Web istemcisi yok), foreign_origin (ekrandaki sayfa uygulamanın kendisine ait değil), failed, unexpected_credential_type, parse_failed: .... Boş bir ilk bağımsız değişken, varsa yüklediğiniz kendi google-services.json dosyanızdaki Web istemcisini kullanır. ID belirtecini sunucunuzda doğrulayın (veya Firebase'e verin: GoogleAuthProvider.credential(idToken)).

signOutGoogle köprü#

window.WebToApk.signOutGoogle(callbackId: String)

Kayıtlı Credential Manager durumunu temizler, böylece bir sonraki signInWithGoogle çağrısı son hesabı sessizce yeniden seçmek yerine hesap seçiciyi yeniden gösterir. Oluşturulan uygulamalar, firebase.auth().signOut() çağrısına ek olarak bunu kullanıcı kaynaklı oturum kapatmada çağırmalıdır.

Örnek

Android'in kayıtlı Google oturum açma durumunu temizler, böylece bir sonraki oturum açmada hesap seçici yeniden gösterilir. Sayfalar normalde bu çağrıyı saran WebToApkAuth.signOutGoogle() Promise yardımcısını kullanır.

Döndürür: hiçbir şey. Yanıt sonra gelir: kabuk window.__webToApkAuth[callbackId](json) işlevini '{"ok":true}' veya '{"ok":false,"error":"..."}' ile çağırır. Gerektirir: hiçbir şey.

Yardımcı (önerilen):

async function signOut() {
  await myBackendSignOut();                          // end your own session first
  if (window.WebToApkAuth) {
    try { await window.WebToApkAuth.signOutGoogle(); } catch (err) { /* nothing to undo */ }
  }
}

Ham çağrı:

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);
}

Kullanıcı hesabını sildiğinde kullanılan, bir Promise'e sarılmış ham çağrı:

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();
}

Notlar: Kullanıcının Firebase'den veya sunucunuzdan oturumunu kapatmaz - bunu kendiniz yapın.

Her belge derlemesinde uygulama çalışma zamanından ve örnek dosyalarından oluşturulur. Markdown olarak okuyun · Tüm aileler.

22.10.2026 tarihinde yayınlanan köprüyle karşılaştırılarak kontrol edildi.