JavaScript köprü API'si
Cihaz ve uygulama bilgileri
Bu telefonun ne olduΔu, hangi derleme olduΔu, kurulum baΕΔ±na kararlΔ± bir tanΔ±mlayΔ±cΔ± ve standart konum ile kamera API'leri.
getUserMedia web standardı#
navigator.mediaDevices.getUserMedia — camera and microphone
Örnek
Standart web kamera ve mikrofon API'si uygulamanΔ±n iΓ§inde Γ§alΔ±ΕΔ±r. Uygulama Android'in kendi izin penceresini gΓΆsterir ve akΔ±ΕΔ± sayfaya verir.
DΓΆner deΔer: bir MediaStream Promise'i veya bir ret (kullanΔ±cΔ± reddettiΔinde ya da anahtar derlemede kapalΔ±ysa NotAllowedError, bΓΆyle bir cihaz yoksa NotFoundError). Gerekenler: AdΔ±m 4'te (EriΕim) Kamera ve/veya Mikrofon. ZIP veya HTML sayfasΔ±ndan derleme yaparsanΔ±z ve kodunuz getUserMedia({ video: … }) veya { audio: … } Γ§aΔΔ±rΔ±yorsa (ya da <input capture>, BarcodeDetector, SpeechRecognition kullanΔ±yorsa) derleme Γ§aΔrΔ±yΔ± bulur ve ilgili izni sizin iΓ§in ekler; { video: false } Kamera eklemez. Web sitesi (URL) derlemesinde kendiniz iΕaretleyin.
Arka kamerayΔ± bir video ΓΆΔesinde gΓΆsterin.
<video id="preview" autoplay playsinline muted></video>
<button id="startCam">Start camera</button>
<script>
document.getElementById('startCam').addEventListener('click', async function () {
if (!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) {
showMessage('Camera is not available here.');
return;
}
try {
var stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' }, // 'user' = front camera
audio: false
});
document.getElementById('preview').srcObject = stream;
} catch (err) {
if (err.name === 'NotAllowedError') showMessage('Camera permission was refused.');
else showMessage('Camera error: ' + err.name);
}
});
</script>YalnΔ±zca mikrofonla bir sesli not kaydedin.
async function recordVoice(seconds) {
var stream;
try {
stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
} catch (err) {
showMessage('Microphone permission was refused.');
return;
}
var chunks = [];
var rec = new MediaRecorder(stream);
rec.ondataavailable = function (e) { chunks.push(e.data); };
rec.onstop = function () {
stream.getTracks().forEach(function (t) { t.stop(); }); // turn the mic off
var blob = new Blob(chunks, { type: rec.mimeType });
document.getElementById('player').src = URL.createObjectURL(blob);
};
rec.start();
setTimeout(function () { rec.stop(); }, seconds * 1000);
}Kamera akΔ±ΕΔ±ndan fotoΔraf Γ§ekin ve kamerayΔ± serbest bΔ±rakΔ±n.
async function snapshot() {
if (!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) return null;
let stream;
try {
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user' } });
} catch (err) {
showMessage(err.name === 'NotFoundError' ? 'No camera on this device.' : 'Camera permission was refused.');
return null;
}
const video = document.createElement('video');
video.srcObject = stream;
await video.play();
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth; canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0);
stream.getTracks().forEach(function (t) { t.stop(); });
return canvas.toDataURL('image/jpeg', 0.9);
}Notlar: Kamera ve mikrofonu birlikte istediΔinizde uygulama kullanΔ±cΔ±dan ikisini birden ister. Derleme sΔ±rasΔ±nda anahtar kapalΔ±ysa istek hiΓ§ izin penceresi aΓ§Δ±lmadan reddedilir; anahtarΔ± aΓ§Δ±p yeniden derleyin. Δ°Εiniz bitince parΓ§alarΔ± her zaman durdurun, yoksa kamera/mikrofon ΔΕΔ±ΔΔ± yanΔ±k kalΔ±r. DRM'li video (Widevine) herhangi bir anahtar olmadan Γ§alΔ±ΕΔ±r. Kamera ve mikrofon hassastΔ±r: bunlarΔ± Play Veri gΓΌvenliΔi formunuzda belirtin.
IdleDetector web standardı#
new IdleDetector() — Idle Detection
Örnek
Standart BoΕta Kalma AlgΔ±lama API'si: kullanΔ±cΔ±nΔ±n telefonu ne zaman kullanmayΔ± bΔ±raktΔ±ΔΔ±nΔ± (bir sΓΌre girdi yok) ya da ekranΔ± kilitlediΔini ve ne zaman geri dΓΆndΓΌΔΓΌnΓΌ ΓΆΔrenin; "uzakta" durumu, canlΔ± bir oturumu duraklatma veya bir kasayΔ± kilitleme iΓ§in.
DΓΆner deΔer: IdleDetector.requestPermission() β 'granted' veya 'denied' (dokunuΕ gerekir); detector.start({threshold, signal}) β Promise (izin yoksa NotAllowedError ile, 60000 ms altΔ±nda TypeError ile reddedilir); ardΔ±ndan userState ('active'/'idle'), screenState ('locked'/'unlocked') ve bir change olayΔ±. Gerekenler: aΓ§Δ±lacak bir anahtar ve Android izni yok.
document.getElementById('away').addEventListener('click', async () => {
if (!('IdleDetector' in window)) return;
if ((await IdleDetector.requestPermission()) !== 'granted') return;
const ac = new AbortController();
const idle = new IdleDetector();
idle.addEventListener('change', () => {
setStatus(idle.userState === 'idle' || idle.screenState === 'locked' ? 'Away' : 'Online');
});
await idle.start({ threshold: 5 * 60000, signal: ac.signal });
stopButton.onclick = () => ac.abort();
});KullanΔ±cΔ± bir kez evet dedikten sonra, yeni bir dokunuΕ olmadan bir sonraki aΓ§Δ±lΔ±Εta izlemeye devam edin:
async function watchAwayIfAllowed() {
if (!('IdleDetector' in window)) return;
const perm = await navigator.permissions.query({ name: 'idle-detection' });
if (perm.state !== 'granted') return; // 'prompt' until requestPermission() ran from a tap
const idle = new IdleDetector();
idle.onchange = () => {
if (idle.screenState === 'locked') pauseLiveSession();
else if (idle.userState === 'active') resumeLiveSession();
};
await idle.start({ threshold: 60000 }); // 1 minute is the smallest threshold
}
watchAwayIfAllowed();KullanΔ±cΔ±nΔ±n otomatik kilit gecikmesini deΔiΕtirmesine izin verin: Γ§alΔ±Εan algΔ±layΔ±cΔ±yΔ± durdurun, yenisini baΕlatΔ±n ve gerΓ§ek hatalarΔ± bildirin:
let vaultWatch = null;
async function setAutoLock(minutes) {
if (vaultWatch) vaultWatch.abort(); // aborting stops the old detector
vaultWatch = new AbortController();
const idle = new IdleDetector();
idle.addEventListener('change', () => {
if (idle.userState === 'idle' || idle.screenState === 'locked') lockVault();
});
try {
await idle.start({ threshold: minutes * 60000, signal: vaultWatch.signal });
} catch (err) {
if (err.name === 'NotAllowedError') showMessage('Tap "Enable auto-lock" first.');
else if (err instanceof TypeError) showMessage('Pick at least 1 minute.');
else throw err;
}
}Notlar: uygulamada "girdi", uygulama ΓΆndeyken kullanΔ±cΔ±nΔ±n BU uygulamaya verdiΔi girdidir; ekran aΓ§Δ±kken baΕka bir uygulama ΓΆndeyse kullanΔ±cΔ± etkin sayΔ±lΔ±r (bir uygulama diΔer uygulamalarΔ±n girdisini gΓΆremez; Android'de Chrome de aynΔ± Εekilde yanΔ±tlar); ekran kapandΔ±ΔΔ±nda veya kilitlendiΔinde boΕta kalma sΓΌresi son dokunuΕtan itibaren iΕler. Δ°zin hatΔ±rlanΔ±r ve navigator.permissions.query({name:'idle-detection'}) onu yanΔ±tlar. Dahili aktarΔ±mlar: __idleState, __idlePermission; kilit/kilit aΓ§ma deΔiΕiklikleri appmint:idle olarak gelir. Yapay zekΓ’yla oluΕturulan uygulamalar Εunu kullanΔ±r: watchIdle().
TextDetector web standardı#
new TextDetector().detect(image) — text recognition (OCR)
Örnek
Bir resimdeki metni telefonun kendisinde okur: bir fiΕ toplamΔ±, bir seri numarasΔ±, bir kartvizit. Google'Δ±n ML Kit tanΔ±yΔ±cΔ±sΔ±nΔ± kullanΔ±r. YapΔ±sΔ±, Chrome'un bir bayrak arkasΔ±nda sunduΔu Shape Detection API'sinin TextDetector yapΔ±sΔ±dΔ±r.
DΓΆner deΔer: bir dizi iΓ§eren Promise, her satΔ±r iΓ§in bir girdi: gΓΆrΓΌntΓΌnΓΌn piksellerinde { rawValue, boundingBox, cornerPoints }. Google Play hizmetleri yoksa NotSupportedError ile, tanΔ±ma baΕarΔ±sΔ±z olursa OperationError ile reddedilir. Gerekenler: aΓ§Δ±lacak bir anahtar ve izin yok (kameradan okumak iΓ§in fotoΔrafΔ± <input type="file" accept="image/*" capture> ile veya bir kamera akΔ±ΕΔ±yla Γ§ekin).
document.getElementById('photo').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file || !('TextDetector' in window)) return;
status.textContent = 'Reading…';
try {
const lines = await new TextDetector().detect(file); // a Blob, <img>, <canvas>, <video> or ImageBitmap
const text = lines.map((l) => l.rawValue).join('\n');
const total = /total\s*[:$€£]?\s*([\d.,]+)/i.exec(text);
status.textContent = total ? 'Total: ' + total[1] : text;
} catch (err) {
status.textContent = 'Could not read the text (' + err.name + ')';
}
});CanlΔ± kamera ΓΆnizlemesinden bir seri numarasΔ± okuyun (oynatΔ±lan bir <video> olduΔu gibi geΓ§ilir, mevcut karesi okunur):
const video = document.querySelector('video');
async function startPreview() {
video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } });
await video.play();
}
document.getElementById('read-serial').addEventListener('click', async () => {
if (!('TextDetector' in window)) return;
const lines = await new TextDetector().detect(video);
const hit = lines.map((l) => l.rawValue).find((t) => /S\/?N[:\s]*[A-Z0-9-]{6,}/i.test(t));
serialField.value = hit ? hit.replace(/^.*S\/?N[:\s]*/i, '') : '';
if (!hit) showMessage('No serial number in view — move closer and try again.');
});boundingBox (gΓΆrΓΌntΓΌ pikselleri) kullanarak tanΔ±nan her satΔ±rΔ± fotoΔrafΔ±n ΓΌstΓΌnde Γ§erΓ§eveleyin:
async function outlineText(img, canvas) {
await img.decode(); // detect() rejects InvalidStateError before it has loaded
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const g = canvas.getContext('2d');
g.drawImage(img, 0, 0);
const lines = await new TextDetector().detect(img);
g.strokeStyle = '#ff3b30';
g.lineWidth = 3;
for (const { boundingBox: b, rawValue } of lines) {
g.strokeRect(b.x, b.y, b.width, b.height);
console.log(rawValue);
}
return lines.length;
}Metin tanΔ±ma yoksa (Google Play hizmetleri yok) tarama dΓΌΔmesini gizleyin ve bir kartvizitten iletiΕim bilgilerini alΔ±n:
const scanBtn = document.getElementById('scan-card');
scanBtn.hidden = !('TextDetector' in window);
document.getElementById('card-photo').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const text = (await new TextDetector().detect(file)).map((l) => l.rawValue).join('\n');
fillContact({
email: (text.match(/[\w.+-]+@[\w-]+\.[\w.]+/) || [''])[0],
phone: (text.match(/\+?\d[\d\s().-]{7,}\d/) || [''])[0],
});
});Notlar: YalnΔ±zca Latin alfabeleri (Ingilizce, ΔΓ°spanyolca, FransΔ±zca, Almanca, Endonezce, Vietnamca, TΓΌrkΓ§e ve diΔerleri); Γinceyi, Devanagari, Japonca, Korece ve ArapΓ§a tanΔ±nmaz. Model Google Play hizmetlerinden gelir: kodunuz kullanΔ±yorsa derleme kurulumda onu ister, aksi halde yeni bir telefonda ilk Γ§aΔrΔ± indirilirken birkaΓ§ saniye bekler. BaΕka bir siteden gelen gΓΆrΓΌntΓΌler CORS'a izin vermelidir (kirlenmiΕ bir canvas SecurityError hatasΔ± verir). Dahili aktarΔ±mlar: __ocrAvailable, __ocrRecognize (appmint:ocr olarak yanΔ±tlanΔ±r). Yapay zekΓ’yla oluΕturulan uygulamalar Εunu kullanΔ±r: recognizeText().
__idlePermission köprü#
window.WebToApk.__idlePermission(request: Boolean): String
IdleDetector.requestPermission() ([request] true, kullanΔ±cΔ± hareketi altΔ±nda Γ§aΔrΔ±lΔ±r) izni kaydeder; false yalnΔ±zca okur. "granted" | "prompt".
Örnek
IdleDetector.requestPermission() ve 'idle-detection' izin durumunun 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ΓΆner deΔer: 'granted' veya 'prompt'. Gerekenler: istek iΓ§in bir kullanΔ±cΔ± hareketi.
Genel API'yi kullanın:
button.onclick = async () => {
const state = await IdleDetector.requestPermission();
console.log(state); // 'granted'
};ΓzelliΔi kontrol edin ve bir reddi "izin verilmedi" olarak ele alΔ±n:
async function askIdlePermission() {
if (!('IdleDetector' in window)) return false;
try {
return (await IdleDetector.requestPermission()) === 'granted';
} catch (err) {
return false;
}
}Bir dokunuΕtan isteyin, sonra algΔ±lamayΔ± baΕlatΔ±n:
startBtn.addEventListener('click', async () => {
if (!(await askIdlePermission())) { showMessage('Idle detection was not allowed.'); return; }
const idle = new IdleDetector();
idle.addEventListener('change', () => console.log(idle.userState));
await idle.start({ threshold: 60000 });
});Notlar: Uygulama kabuΔunda uygulanmΔ±ΕtΔ±r (IdleAndRelatedApps.kt).
__idleState köprü#
window.WebToApk.__idleState(): String
IdleDetector: uygulamanΔ±n kendi girdisinden ve tuΕ kilidinden `{idleMs, locked}`.
Örnek
IdleDetector arkasΔ±ndaki dahili aktarΔ±m: kullanΔ±cΔ±nΔ±n en son girdi vermesinden bu yana geΓ§en sΓΌre ve ekranΔ±n kilitli olup olmadΔ±ΔΔ±. Sayfalar standart API'yi kullanΔ±r; bunu asla doΔrudan Γ§aΔΔ±rmayΔ±n; __ yΓΆntemleri haber verilmeden deΔiΕebilir.
DΓΆner deΔer: JSON {idleMs, locked}. Ekran ve uygulama deΔiΕiklikleri aynΔ± yapΔ±yla appmint:idle olayΔ± olarak iletilir. Gerekenler: hiΓ§bir Εey.
Genel API'yi kullanın:
const idle = new IdleDetector();
idle.onchange = () => console.log(idle.userState, idle.screenState);
await idle.start({ threshold: 60000 });Ekran kapanΔ±nca izlemeyi bir AbortController ile durdurun:
const ctl = new AbortController();
const idle = new IdleDetector();
idle.addEventListener('change', () => {
if (idle.userState === 'idle') showAwayBanner();
});
await idle.start({ threshold: 60000, signal: ctl.signal });
// later: ctl.abort();Ekran kilitlendiΔinde uygulamayΔ± kilitleyin:
if ('IdleDetector' in window && (await IdleDetector.requestPermission()) === 'granted') {
const d = new IdleDetector();
d.onchange = () => { if (d.screenState === 'locked') showPinScreen(); };
await d.start({ threshold: 60000 });
}Notlar: Uygulama kabuΔunda uygulanmΔ±ΕtΔ±r (IdleAndRelatedApps.kt).
__permissionState köprü#
window.WebToApk.__permissionState(name: String): String
Bir W3C izin adΔ±nΔ±n Android'in gerΓ§ek izinlerinden Δ°zinler API'si durumu: "granted" | "denied" | "prompt"; ya da kabuk o adΔ± yanΔ±tlamΔ±yorsa "" (sayfanΔ±n sorgusu o zaman WebView'in kendi uygulamasΔ±na gider).
Örnek
navigator.permissions.query({ name }) 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ΓΆner deΔer: 'granted', 'denied', 'prompt' veya uygulamanΔ±n yanΔ±tlamadΔ±ΔΔ± bir ad iΓ§in '' (sorgu o zaman WebView'in kendisine gider). Gerekenler: aΓ§Δ±lacak bir anahtar yok.
Genel API'yi kullanın:
const status = await navigator.permissions.query({ name: 'camera' });
showCameraHint(status.state); // 'granted' | 'denied' | 'prompt'
status.addEventListener('change', () => showCameraHint(status.state));Birden Γ§ok izni aynΔ± anda kontrol edin:
const names = ['camera', 'microphone', 'geolocation', 'notifications'];
const states = await Promise.all(names.map((name) =>
navigator.permissions.query({ name }).then((s) => s.state, () => 'unknown')));
names.forEach((name, i) => console.log(name, states[i]));YalnΔ±zca durum denied deΔilse isteyin ve olduΔunda ne yapΔ±lacaΔΔ±nΔ± sΓΆyleyin:
async function ensureLocation() {
const s = await navigator.permissions.query({ name: 'geolocation' });
if (s.state === 'denied') { showMessage('Turn location on in the phone settings.'); return null; }
return new Promise((ok, fail) => navigator.geolocation.getCurrentPosition(ok, fail));
}Notlar: camera, microphone, geolocation, notifications, screen-wake-lock, clipboard-read, clipboard-write adlarΔ±nΔ± yanΔ±tlar. Derlemede kapalΔ± bΔ±rakΔ±lan (veya izni manifestte olmayan) bir yetenek denied olur. CanlΔ± durumlar appmint:permissions-changed olayΔ±nda (her izin penceresinden sonra tetiklenir) ve sayfa yeniden gΓΆrΓΌnΓΌr olduΔunda yeniden okunur.
getAppName köprü#
window.WebToApk.getAppName(): String
OluΕturucunun sihirbazda seΓ§tiΔi uygulama adΔ±; baΕlatΔ±cΔ±nΔ±n gΓΆsterdiΔi ad.
Örnek
Derleme sihirbazΔ±nda seΓ§tiΔiniz uygulama adΔ±nΔ± verir; baΕlatΔ±cΔ± simgesinin altΔ±ndaki ad.
DΓΆner deΔer: hemen bir dize. Gerekenler: hiΓ§bir Εey.
GerΓ§ek uygulama adΔ±nΔ± bir baΕlΔ±kta ve bir paylaΕΔ±m metninde kullanΔ±n.
var appName = (window.WebToApk && window.WebToApk.getAppName)
? WebToApk.getAppName()
: document.title; // in a browser: the page title
document.getElementById('welcome').textContent = 'Welcome to ' + appName;
document.getElementById('shareBtn').addEventListener('click', function () {
if (navigator.share) navigator.share({ text: 'Try ' + appName + '!' });
});Uygulama adΔ±nΔ± sayfa baΕlΔ±ΔΔ±na ve bir baΕlΔ±Δa koyun:
if (window.WebToApk && WebToApk.getAppName) {
const name = WebToApk.getAppName();
document.title = name;
document.querySelector('h1').textContent = name;
}Uygulama adΔ±nΔ± ve sΓΌrΓΌmΓΌnΓΌ belirten bir destek e-postasΔ± oluΕturun:
function supportMailto() {
const b = window.WebToApk;
const name = b && b.getAppName ? b.getAppName() : 'our app';
const version = b && b.getAppVersion ? b.getAppVersion() : 'web';
const subject = encodeURIComponent('Help with ' + name + ' ' + version);
return 'mailto:[email protected]?subject=' + subject;
}
document.getElementById('contact').href = supportMailto();Notlar: Bu, sayfanΔ±n <title> deΔil, sihirbazdaki addΔ±r. Γalışma sΔ±rasΔ±nda deΔiΕmez. SΓΌrΓΌm iΓ§in Εunu kullanΔ±n: getAppVersion().
getAppVersion köprü#
window.WebToApk.getAppVersion(): String
YΓΌklΓΌ paketin versionName deΔeri, ΓΆr. "1.4.2"; derleme sΔ±rasΔ±nda oluΕturucunun belirlediΔi dizedir, versionCode deΔil. Paket okunamazsa "1.0" deΔerine dΓΆner; bΓΆylece bir sayfa onu null kontrolΓΌ olmadan yazdΔ±rabilir.
Örnek
YΓΌklΓΌ uygulamanΔ±n sΓΌrΓΌm adΔ±nΔ± verir, ΓΆrneΔin "1.4.2".
DΓΆner deΔer: hemen bir dize. Gerekenler: hiΓ§bir Εey.
SΓΌrΓΌmΓΌ HakkΔ±nda ekranΔ±nda gΓΆsterin.
var version = (window.WebToApk && window.WebToApk.getAppVersion)
? WebToApk.getAppVersion()
: 'web';
document.getElementById('about').textContent = 'Version ' + version;YΓΌklΓΌ sΓΌrΓΌm eskiyse gΓΌncelleme isteyin:
function isOlder(a, b) { // "1.4.2" < "1.10.0"
const x = a.split('.').map(Number), y = b.split('.').map(Number);
for (let i = 0; i < Math.max(x.length, y.length); i++) {
if ((x[i] || 0) !== (y[i] || 0)) return (x[i] || 0) < (y[i] || 0);
}
return false;
}
if (window.WebToApk && WebToApk.getAppVersion && isOlder(WebToApk.getAppVersion(), '1.5.0')) {
document.getElementById('update-banner').hidden = false;
}Bir hata raporuna getDeviceInfo() iΓ§indeki sΓΌrΓΌmΓΌ ve sΓΌrΓΌm kodunu ekleyin:
function reportInfo() {
const b = window.WebToApk;
if (!(b && b.getAppVersion)) return 'web';
let text = 'v' + b.getAppVersion();
if (b.getDeviceInfo) {
const info = JSON.parse(b.getDeviceInfo());
text += ' (build ' + info.app.versionCode + ')';
}
return text;
}
document.getElementById('report').value = reportInfo();Notlar: Bu, derleme sΔ±rasΔ±nda belirlediΔiniz sΓΌrΓΌm ADIDIR, sΓΌrΓΌm kodu deΔil. Paket okunamazsa "1.0" dΓΆner; bu yΓΌzden asla boΕ deΔildir. SΓΌrΓΌm kodu ve kurulum tarihleri getDeviceInfo() iΓ§inde, Εu baΕlΔ±k altΔ±ndadΔ±r: app.
getDeviceInfo köprü#
window.WebToApk.getDeviceInfo(): String
WebToApk.getDeviceInfo() -> JSON dizesi, izin GEREKMEZ WebToApk.getPhoneIdentity() -> operatΓΆr/SIM, Telefon izni gerekir WebToApk.getInstallId() -> kurulum baΕΔ±na kararlΔ± UUID
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Cihaz / uygulama bilgileri.
Örnek
Telefon, Android, ekran, uygulamanΔ±z ve mevcut durum (pil, bellek, aΔ) hakkΔ±ndaki bilgileri tek Γ§aΔrΔ±da verir.
DΓΆner deΔer: hemen bir JSON dizesi; JSON.parse kullanΔ±n. ΓΓΆst dΓΌzey anahtarlar: android, hardware, screen, app, runtime, installId. Gerekenler: hiΓ§bir Εey; izin yok.
Telefon bilgilerini gΓΆsterin.
function showPhoneInfo() {
if (!(window.WebToApk && window.WebToApk.getDeviceInfo)) {
document.getElementById('out').textContent = navigator.userAgent; // browser: only the user agent
return;
}
var info = JSON.parse(WebToApk.getDeviceInfo());
document.getElementById('out').innerHTML =
'Android: ' + info.android.release + ' (SDK ' + info.android.sdkInt + ')<br>' +
'Version ID: ' + info.android.buildId + '<br>' +
'Build number: ' + info.android.incremental + '<br>' +
'Phone: ' + info.hardware.manufacturer + ' ' + info.hardware.model + '<br>' +
'Screen: ' + info.screen.widthPx + 'x' + info.screen.heightPx + ' @' + info.screen.refreshRate + 'Hz<br>' +
'Battery: ' + info.runtime.batteryLevel + '%' + (info.runtime.charging ? ' (charging)' : '') + '<br>' +
'Network: ' + info.runtime.networkType + '<br>' +
'App: ' + info.app.versionName + ' (' + info.app.versionCode + ')<br>' +
'WebView: ' + info.app.webViewPackage;
}TΓΌm anahtarlar:
{
"android": { "release": "14", "sdkInt": 34, "codename": "REL", "buildId": "UP1A.231005.007", "incremental": "R.1a2b3c", "display": "…", "fingerprint": "…", "securityPatch": "2026-08-05" },
"hardware": { "manufacturer": "OPPO", "brand": "OPPO", "model": "CPH2269", "device": "…", "product": "…", "board": "…", "hardware": "…", "abis": ["arm64-v8a"], "socManufacturer": "…", "socModel": "…", "isEmulator": false },
"screen": { "widthPx": 720, "heightPx": 1600, "density": 2, "densityDpi": 320, "refreshRate": 90, "nightMode": true },
"app": { "packageName": "com.example.app", "versionName": "1.0", "versionCode": 1, "targetSdk": 35, "firstInstallTime": 1737000000000, "lastUpdateTime": 1737000000000, "installer": "com.android.vending", "webViewPackage": "com.google.android.webview 131.0" },
"runtime": { "totalMemoryBytes": 4000000000, "availableMemoryBytes": 1500000000, "lowMemory": false, "storageFreeBytes": 20000000000, "storageTotalBytes": 64000000000, "batteryLevel": 80, "charging": false, "locale": "en-IN", "timezone": "Asia/Kolkata", "networkType": "wifi" },
"installId": "3f2b8c1e-…"
}Depolama veya belleΔi az olan bir telefonda uyarΔ±n; bΓΌyΓΌk bir indirmeden ΓΆnce.
function canDownload(bytesNeeded) {
if (!(window.WebToApk && WebToApk.getDeviceInfo)) return true; // browser: let the download try
const r = JSON.parse(WebToApk.getDeviceInfo()).runtime;
if (r.storageFreeBytes < bytesNeeded * 2) { showMessage('Not enough free storage.'); return false; }
if (r.lowMemory) showMessage('The phone is low on memory; this may be slow.');
return true;
}Notlar: socManufacturer / socModel yalnΔ±zca Android 12+ sΓΌrΓΌmΓΌnde vardΔ±r. networkType, wifi, cellular, ethernet, other, none veya unknown olur. installer, Play kurulumlarΔ± iΓ§in com.android.vending, yandan yΓΌklemelerde boΕtur. DeΔerler Γ§aΔΔ±rdΔ±ΔΔ±nΔ±z anda okunur; pili veya aΔΔ± yenilemek iΓ§in yeniden Γ§aΔΔ±rΔ±n. IMEI veya seri numarasΔ± yoktur: Android bunlarΔ± tΓΌm uygulamalara kapatΔ±r; Εunu kullanΔ±n: getInstallId().
getInstallId köprü#
window.WebToApk.getInstallId(): String
WebToApk.getDeviceInfo() -> JSON dizesi, izin GEREKMEZ WebToApk.getPhoneIdentity() -> operatΓΆr/SIM, Telefon izni gerekir WebToApk.getInstallId() -> kurulum baΕΔ±na kararlΔ± UUID
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Cihaz / uygulama bilgileri.
Örnek
UygulamanΔ±zΔ±n bu kurulumu iΓ§in aynΔ± kalan rastgele bir kimlik verir.
DΓΆner deΔer: hemen bir dize ("3f2b…-…" gibi bir UUID). Gerekenler: hiΓ§bir Εey.
Sunucunuz iΓ§in veya "cihaz baΕΔ±na bir ΓΌcretsiz deneme" kontrolΓΌ iΓ§in bir cihaz anahtarΔ± olarak kullanΔ±n.
function deviceKey() {
if (window.WebToApk && window.WebToApk.getInstallId) {
return WebToApk.getInstallId();
}
// In a browser: keep your own random ID in localStorage (per browser, cleared with site data).
var k = localStorage.getItem('installId');
if (!k) {
k = 'w-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 10);
localStorage.setItem('installId', k);
}
return k;
}
fetch('https://api.example.com/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ device: deviceKey() })
});KimliΔi sunucunuza bir baΕlΔ±kla gΓΆnderin ve URL'nin dΔ±ΕΔ±nda tutun.
async function apiGet(path) {
const id = (window.WebToApk && WebToApk.getInstallId) ? WebToApk.getInstallId() : null;
const res = await fetch('https://api.example.com' + path, {
headers: id ? { 'X-Install-Id': id } : {}
});
return res.json();
}ΓΓΆkme raporlarΔ±na ekleyin; bΓΆylece bir kurulumun sorunlarΔ± bulunabilir.
if (window.WebToApk && WebToApk.setCrashUserId && WebToApk.getInstallId) {
// returns false when Crash reports are off or the id has other characters
const ok = WebToApk.setCrashUserId(WebToApk.getInstallId());
if (!ok) console.log('crash user id not set');
}Notlar: Kimlik ilk kullanΔ±mda oluΕturulur ve uygulamanΔ±n depolama alanΔ±nda tutulur. Uygulama gΓΌncellemelerinden sonra aynΔ± kalΔ±r. KullanΔ±cΔ± uygulamayΔ± kaldΔ±rΔ±rsa veya verilerini temizlerse deΔiΕir. Bir donanΔ±m kimliΔi deΔildir; Android uygulamalara IMEI veya seri numarasΔ± vermez. AynΔ± deΔer getDeviceInfo() iΓ§inde de installId.
getPhoneIdentity köprü#
window.WebToApk.getPhoneIdentity(): String
WebToApk.getDeviceInfo() -> JSON dizesi, izin GEREKMEZ WebToApk.getPhoneIdentity() -> operatΓΆr/SIM, Telefon izni gerekir WebToApk.getInstallId() -> kurulum baΕΔ±na kararlΔ± UUID
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Cihaz / uygulama bilgileri.
Örnek
Mobil operatΓΆr ve SIM bilgilerini verir: operatΓΆr adΔ±, SIM ΓΌlkesi, operatΓΆr kodu, telefon tΓΌrΓΌ ve SIM durumu.
DΓΆner deΔer: hemen bir JSON dizesi; JSON.parse kullanΔ±n: { carrierName, simCountryIso, networkCountryIso, simOperator, phoneType, simState, hardwareIdAvailable: false } veya { error }. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Telefon seΓ§eneΔini aΓ§Δ±n; aksi halde Εunu dΓΆndΓΌrΓΌr: { "error": "not_enabled" }.
OperatΓΆrΓΌ gΓΆsterin ve ΓΌlke kodunu seΓ§in.
function showCarrier() {
if (!(window.WebToApk && window.WebToApk.getPhoneIdentity)) return;
var p = JSON.parse(WebToApk.getPhoneIdentity());
if (p.error === 'not_enabled') { showMessage('Turn on Phone when you build the app'); return; }
if (p.error) { showMessage('Could not read SIM info: ' + p.error); return; }
if (p.simState !== 'ready') {
showMessage('No SIM ready (' + p.simState + ')'); // absent | pin_required | network_locked | unknown
return;
}
document.getElementById('carrier').textContent = p.carrierName; // e.g. "Jio 4G"
document.getElementById('country').value = p.simCountryIso.toUpperCase(); // e.g. "IN"
}Bir kayΔ±t formu iΓ§in SIM'in ΓΌlkesinden bir arama kodu seΓ§in.
const DIAL = { IN: '+91', US: '+1', GB: '+44', DE: '+49' };
function defaultDialCode() {
if (!(window.WebToApk && WebToApk.getPhoneIdentity)) return '+1';
const p = JSON.parse(WebToApk.getPhoneIdentity());
if (p.error || p.simState !== 'ready') return '+1';
return DIAL[p.simCountryIso.toUpperCase()] || '+1';
}
document.getElementById('dial').value = defaultDialCode();YalnΔ±zca Wi-Fi'li bir tableti telefondan ayΔ±rt edin: phoneType.
if (window.WebToApk && WebToApk.getPhoneIdentity) {
const p = JSON.parse(WebToApk.getPhoneIdentity());
if (!p.error && p.phoneType === 'none') {
document.getElementById('sms-login').hidden = true; // no cellular radio: hide SMS sign-in
}
}Notlar: phoneType, gsm, cdma, sip veya none olur (yalnΔ±zca Wi-Fi'li tabletler). simOperator, MCC+MNC kodudur (ΓΆr. "40445"). IMEI, MEID veya seri numarasΔ± yoktur; hardwareIdAvailable her zaman false olur, Γ§ΓΌnkΓΌ Android 10'dan beri tΓΌm uygulamalardan gizler; kararlΔ± bir kimlik iΓ§in getInstallId() kullanΔ±n. Telefon anahtarΔ± Play sayfanΔ±za hassas bir izin ekler; ne iΓ§in kullandΔ±ΔΔ±nΔ±zΔ± Veri gΓΌvenliΔi formunda belirtin.
isTv köprü#
window.WebToApk.isTv(): Boolean
Uygulama bir televizyonda (Android TV, Google TV, Fire TV) Γ§alΔ±ΕΔ±yorsa doΔrudur.
Örnek
Sayfaya uygulamanΔ±n bir televizyonda (Android TV, Google TV, Fire TV) Γ§alΔ±Εtattigini bildirir; bΓΆylece uzaktan kumandaya uygun bir dΓΌzen gΓΆsterebilir.
DΓΆner deΔer: true veya false (eΕzamanlΔ± olarak). Gerekenler: hiΓ§bir Εey. SihirbazdΔ± Android TV desteΔi aΓ§Δ±kken uygulama TV baΕlatΔ±cΔ±sΔ±nda bir TV afiΕi de alΔ±r ve TV'de sayfa net bir odak halkasΔ± alΔ±r; baΔlantΔ±lar, dΓΌΔmeler, alanlar ve onclick ya da dΓΌΔme rolΓΌyle baΔlanmΔ±Ε ΓΆΔeler kumandanΔ±n oklarΔ±yla eriΕilebilir olur; OK odaktaki ΓΆΔeye tΔ±klar ve Geri telefondaki gibi Γ§alΔ±ΕΔ±r.
var onTv = !!(window.WebToApk && typeof window.WebToApk.isTv === 'function' && window.WebToApk.isTv());
if (onTv) {
document.documentElement.classList.add('tv'); /* bigger text, no hover-only menus */
document.querySelector('#play').focus(); /* start the remote on the main action */
}html.tv body { font-size: 22px; }
html.tv :focus-visible { transform: scale(1.05); }TV iΓ§in farklΔ± bir ana ekran seΓ§in ve telefon dΓΌzenini varsayΔ±lan olarak koruyun.
function isTv() {
return !!(window.WebToApk && typeof WebToApk.isTv === 'function' && WebToApk.isTv());
}
history.replaceState({}, '', isTv() ? '/tv-home' : '/home');
if (isTv()) document.querySelectorAll('.touch-only').forEach(function (el) { el.hidden = true; });Notlar: Android TV emΓΌlatΓΆrΓΌ ve D-pad ile test edin. TV'lerde Google Play'de yayΔ±nlamak ayrΔ± bir adΔ±mdΔ±r: Play Console'da uygulamayΔ± Android TV form faktΓΆrΓΌne dahil edin (SΓΌrΓΌm β GeliΕmiΕ ayarlar β Form faktΓΆrleri) ve bir TV ekran gΓΆrΓΌntΓΌsΓΌ ekleyin.