JavaScript köprü API'si
Dosyalar: kullanΔ±cΔ±nΔ±n izin verdiΔi klasΓΆr
Bir kez seΓ§ilen, sonra okunabilir ve yazΔ±labilir olan, yeniden baΕlatmalardan sonra da geΓ§erli kalan izinli bir dizin.
WebToApkFS.clearAccess yardımcı#
WebToApkFS.clearAccess()
Örnek
Δ°zin verilen klasΓΆrΓΌ unutur ve izni Android'e geri verir.
DΓΆner deΔer: hiΓ§bir Εey (eΕzamanlΔ±). Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin.
KlasΓΆrΓΌn adΔ±nΔ±n yanΔ±nda her zaman baΔlantΔ±yΔ± kesme yolu sunun:
document.getElementById('disconnect').addEventListener('click', function () {
if (!window.WebToApkFS) return;
window.WebToApkFS.clearAccess();
console.log('still connected?', window.WebToApkFS.hasAccess()); // false
document.getElementById('folder-name').textContent = 'No folder chosen';
document.getElementById('choose-folder').hidden = false;
});Mevcut duruma gΓΆre baΔlanan veya baΔlantΔ±yΔ± kesen tek bir dΓΌΔme:
var btn = document.getElementById('folder-toggle');
function paint() {
btn.textContent = window.WebToApkFS.hasAccess() ? 'Disconnect folder' : 'Connect a folder';
}
btn.addEventListener('click', async function () {
if (!window.WebToApkFS) return;
if (window.WebToApkFS.hasAccess()) {
if (!confirm('Stop saving to this folder? Your files stay where they are.')) return;
window.WebToApkFS.clearAccess();
} else {
await window.WebToApkFS.requestAccess();
}
paint();
});
if (window.WebToApkFS) paint();Hesap deΔiΕtirin: klasΓΆrΓΌ oturum aΓ§Δ±k durumunun geri kalanΔ±yla birlikte unutun:
function switchAccount() {
sessionStorage.clear();
if (window.WebToApkFS) window.WebToApkFS.clearAccess(); // the next account picks its own folder
showLoginScreen();
}Notlar: Dosyalar olduΔu yerde kalΔ±r; uygulama onlara artΔ±k ulaΕamaz. Bir klasΓΆrΓΌ yeniden kullanmak iΓ§in bir dokunuΕtan WebToApkFS.requestAccess() Γ§aΔrΔ±n.
WebToApkFS.delete yardımcı#
WebToApkFS.delete(relativePath, options)
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§indeki bir dosyayΔ± veya klasΓΆrΓΌ siler.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean: silindiyse true. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
Sorduktan sonra tek bir dosyayΔ± silin:
if (window.WebToApkFS && confirm('Delete notes/old.txt?')) {
var ok = window.WebToApkFS.delete('notes/old.txt');
if (!ok) alert('Could not delete the file.');
}Bir klasΓΆrΓΌ ve iΓ§indeki her Εeyi silin; Εunu verin: { recursive: true }:
if (window.WebToApkFS && confirm('Delete the whole 2025 folder?')) {
var gone = window.WebToApkFS.delete('notes/2025', { recursive: true });
console.log(gone ? 'deleted' : 'not deleted');
}30 gΓΌnden eski dΔ±Εa aktarmalarΔ± dosya dosya temizleyin:
function pruneOldExports() {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return 0;
var cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
var removed = 0;
window.WebToApkFS.list('exports').forEach(function (e) {
if (e.isDirectory || e.lastModified >= cutoff) return;
if (window.WebToApkFS.delete('exports/' + e.name)) removed++;
});
return removed;
}
if (confirm('Delete exports older than 30 days?')) {
document.getElementById('status').textContent = pruneOldExports() + ' old exports deleted';
}Notlar: { recursive: true } olmadan bir klasΓΆr yalnΔ±zca boΕsa silinir. Δ°zin verilen klasΓΆrΓΌn kendisi ('') asla silinemez. Silme anΔ±nda olur ve Γ§ΓΆp kutusu yoktur; bu yΓΌzden her zaman ΓΆnce kullanΔ±cΔ±ya sorun.
WebToApkFS.getAccessUri yardımcı#
WebToApkFS.getAccessUri()
Örnek
Dosyalarun nereye gittiΔini kullanΔ±cΔ±ya gΓΆsterebilmeniz iΓ§in izin verilen klasΓΆrΓΌn adresini verir.
DΓΆner deΔer: eΕzamanlΔ± olarak bir dize: content://com.android.externalstorage.documents/tree/primary%3ADocuments%2FNotes gibi bir aΔaΓ§ URI'si ya da izin verilmiΕ klasΓΆr yoksa ''. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin.
BaΔlantΔ±yΔ± kes dΓΌΔmesinin yanΔ±nda okunabilir bir klasΓΆr adΔ± gΓΆsterin:
function connectedFolderName() {
if (!window.WebToApkFS) return '';
var uri = window.WebToApkFS.getAccessUri();
if (!uri) return '';
var tail = uri.split('/tree/')[1] || '';
try { tail = decodeURIComponent(tail); } catch (e) {}
return tail.split(':').pop() || tail; // "Documents/Notes"
}
var name = connectedFolderName();
document.getElementById('folder-name').textContent = name ? 'Folder: ' + name : 'No folder chosen';KullanΔ±cΔ±nΔ±n son ziyaretten bu yana farklΔ± bir klasΓΆr seΓ§tiΔini fark edin ve eski klasΓΆr hakkΔ±nda ΓΆnbelleΔe aldΔ±ΔΔ±nΔ±z her Εeyi yeniden oluΕturun:
function checkFolderChanged() {
if (!window.WebToApkFS) return;
var uri = window.WebToApkFS.getAccessUri();
var last = '';
try { last = localStorage.getItem('folderUri') || ''; } catch (e) {}
if (uri && uri !== last) {
rebuildFileIndex(); // your app: re-read the new folder
try { localStorage.setItem('folderUri', uri); } catch (e) {}
}
}
checkFolderChanged();KlasΓΆrΓΌ unutan ve gittiΔini doΔrulayan bir BaΔlantΔ±yΔ± kes dΓΌΔmesi:
document.getElementById('disconnect').addEventListener('click', function () {
if (!window.WebToApkFS || !window.WebToApkFS.getAccessUri()) return;
if (!confirm('Stop saving to this folder? Your files stay where they are.')) return;
window.WebToApkFS.clearAccess();
var still = window.WebToApkFS.getAccessUri();
document.getElementById('folder-name').textContent = still ? 'Could not disconnect' : 'No folder chosen';
});Notlar: Dosya yΓΆntemleri bu URI'yi almaz; izin verilmiΕ klasΓΆre gΓΆre gΓΆreli yollar alΔ±r ('notes/today.txt'). URI biΓ§imi kullanΔ±cΔ±nΔ±n seΓ§tiΔi Dosyalar saΔlayΔ±cΔ±sΔ±na aittir; bu yΓΌzden yalnΔ±zca gΓΆrΓΌntΓΌleme iΓ§in kullanΔ±n.
WebToApkFS.hasAccess yardımcı#
WebToApkFS.hasAccess()
Örnek
KullanΔ±cΔ±nΔ±n uygulamaya zaten bir klasΓΆr verip vermediΔini sΓΆyler.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin.
YanΔ±ta gΓΆre "KlasΓΆr seΓ§" veya dosya listesini gΓΆsterin:
function renderFolderScreen() {
if (!window.WebToApkFS) {
document.getElementById('folder-panel').hidden = true; // not in the app, or not enabled
return;
}
var connected = window.WebToApkFS.hasAccess();
document.getElementById('choose-folder').hidden = connected;
document.getElementById('file-list').hidden = !connected;
if (connected) {
var entries = window.WebToApkFS.list('');
document.getElementById('file-list').textContent =
entries.map(function (e) { return e.name; }).join('\n');
}
}YalnΔ±zca bir klasΓΆr baΔlΔ±yken otomatik kaydedin ve baΔlΔ± deΔilse bunu sΓΆyleyin:
var saveTimer = null;
document.getElementById('editor').addEventListener('input', function () {
clearTimeout(saveTimer);
saveTimer = setTimeout(function () {
var status = document.getElementById('status');
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) {
status.textContent = 'Choose a folder to turn on autosave';
return;
}
var ok = window.WebToApkFS.writeText('notes/draft.txt', document.getElementById('editor').value);
status.textContent = ok ? 'Saved' : 'Could not save';
}, 800);
});BaΕlangΔ±Γ§ta, bir klasΓΆr hatΔ±rlanΔ±yorsa son notu yeniden aΓ§Δ±n, aksi halde karΕΔ±lama ekranΔ±nΔ± gΓΆsterin:
window.addEventListener('load', function () {
var fs = window.WebToApkFS;
if (!fs || !fs.hasAccess()) {
showWelcome(); // your app: explains "Choose folder"
return;
}
var last = 'notes/today.txt';
try { last = localStorage.getItem('lastNote') || last; } catch (e) {}
document.getElementById('editor').value = fs.readText(last);
});Notlar: YalnΔ±zca uygulamanΔ±n bir klasΓΆrΓΌ hatΔ±rladΔ±ΔΔ±nΔ± sΓΆyler. KullanΔ±cΔ± o klasΓΆrΓΌ sildiyse veya taΕΔ±dΔ±ysa list(''), [] dΓΆndΓΌrΓΌr; yeniden "KlasΓΆr seΓ§" teklif edin. window.WebToApkFS, sayfa yΓΌklenmeyi bitirdiΔinde gelir; yΓΌkleme sΔ±rasΔ±nda ham olanΔ± kullanΔ±n: window.WebToApk.hasFolderAccess() === 'true'.
WebToApkFS.isAvailable yardımcı#
WebToApkFS.isAvailable()
Örnek
Bu uygulamanΔ±n kullanΔ±cΔ±nΔ±n izin verdiΔi bir klasΓΆrΓΌ hiΓ§ kullanabilip kullanamayacaΔΔ±nΔ± sΓΆyler.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean: derlemede klasΓΆr eriΕimi aΓ§Δ±ksa true. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin; bu olmadan (ve GΓΌvenli Anahtarlar olmadan) window.WebToApkFS sayfaya eklenmez; yalnΔ±zca GΓΌvenli Anahtarlar ile vardΔ±r ve Εunu yanΔ±tlar: false.
window.WebToApkFS sayfanΔ±n ilk betiΔi Γ§alΔ±Εmadan ΓΆnce eklenir; yaklaΕΔ±k 2021'den eski WebView'lerde yalnΔ±zca sayfa yΓΌklenmeyi bitirdiΔinde gelir. BunlarΔ± da kapsamak iΓ§in karar vermeden ΓΆnce kΔ±saca bekleyin:
function whenFolderHelperReady(done) {
var tries = 0;
(function check() {
if (window.WebToApkFS) return done(window.WebToApkFS);
if (++tries > 30) return done(null); // in a browser, or the build did not enable it
setTimeout(check, 100);
})();
}
whenFolderHelperReady(function (fs) {
var usable = !!(fs && fs.isAvailable());
document.getElementById('folder-panel').hidden = !usable;
});Bir dΓΌΔme dokunuΕunun iΓ§inde sayfa Γ§oktan yΓΌklenmiΕtir; bu yΓΌzden doΔrudan kontrol yeterlidir:
if (window.WebToApkFS && window.WebToApkFS.isAvailable()) {
// show the folder features
}Δ°ki kontrolΓΌ, tΓΌm klasΓΆr ekranΔ±nΔ± yΓΆnlendiren tek bir duruma dΓΆnΓΌΕtΓΌrΓΌn:
function folderState() {
var fs = window.WebToApkFS;
if (!fs || !fs.isAvailable()) return 'unsupported'; // this build has no folder access
return fs.hasAccess() ? 'ready' : 'needs-folder';
}
var state = folderState();
document.getElementById('folder-panel').hidden = state === 'unsupported';
document.getElementById('choose-folder').hidden = state !== 'needs-folder';
document.getElementById('export').disabled = state !== 'ready';Notlar: Bu, henΓΌz bir klasΓΆr seΓ§ilip seΓ§ilmediΔi hakkΔ±nda bir Εey sΓΆylemez; bunun iΓ§in WebToApkFS.hasAccess() kullanΔ±n. Sayfa yΓΌklenmeden ΓΆnce ham window.WebToApk.isFolderAccessEnabled() (dize "true"/"false") aynΔ± soruyu yanΔ±tlar.
WebToApkFS.list yardımcı#
WebToApkFS.list(relativePath)
Örnek
Δ°zin verilen klasΓΆrΓΌn bir klasΓΆrΓΌndeki dosyalarΔ± ve alt klasΓΆrleri listeler.
DΓΆner deΔer: eΕzamanlΔ± olarak bir dizi: [{ name, uri, isDirectory, length, lastModified }] (length bayt cinsinden, lastModified 1970'ten beri ms cinsinden). Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
Basit bir dosya gezgini ('' izin verilen klasΓΆrΓΌn kendisidir):
function renderFolder(path) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return;
var ul = document.getElementById('files');
ul.innerHTML = '';
window.WebToApkFS.list(path)
.sort(function (a, b) { return (b.isDirectory - a.isDirectory) || a.name.localeCompare(b.name); })
.forEach(function (e) {
var li = document.createElement('li');
li.textContent = (e.isDirectory ? '[folder] ' : '') + e.name +
(e.isDirectory ? '' : ' (' + e.length + ' bytes, ' + new Date(e.lastModified).toLocaleDateString() + ')');
if (e.isDirectory) li.onclick = function () { renderFolder(path ? path + '/' + e.name : e.name); };
ul.appendChild(li);
});
}
renderFolder('');TΓΌm Markdown notlarΔ±nΔ± toplamak iΓ§in her alt klasΓΆrΓΌ gezin (Εuna verebileceΔiniz yollar: readText):
function findNotes(path, out) {
out = out || [];
window.WebToApkFS.list(path).forEach(function (e) {
var full = path ? path + '/' + e.name : e.name;
if (e.isDirectory) findNotes(full, out);
else if (/\.md$/i.test(e.name)) out.push(full);
});
return out;
}
if (window.WebToApkFS && window.WebToApkFS.hasAccess()) {
var notes = findNotes('');
document.getElementById('count').textContent = notes.length + ' notes';
}En yeni yedeΔi ve yedeklerin ne kadar yer kapladΔ±ΔΔ±nΔ± bulun:
function backupSummary() {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return null;
var files = window.WebToApkFS.list('backups').filter(function (e) { return !e.isDirectory; });
if (!files.length) return null;
var newest = files.reduce(function (a, b) { return b.lastModified > a.lastModified ? b : a; });
var bytes = files.reduce(function (sum, e) { return sum + e.length; }, 0);
return { newest: 'backups/' + newest.name, count: files.length, kb: Math.round(bytes / 1024) };
}
var s = backupSummary();
document.getElementById('backup-info').textContent = s
? s.count + ' backups, ' + s.kb + ' KB. Latest: ' + s.newest
: 'No backups yet';Notlar: Boş klasör, olmayan klasör, dosya olan bir yol, .. içeren bir yol ve izin verilmiş klasörün olmaması hepsi [] döndürür. Liste sıralı değildir. Her uri ayrıca WebToApkFS.stat() ile de çalışır ve WebToApkFS.readBytes().
WebToApkFS.mkdir yardımcı#
WebToApkFS.mkdir(relativePath)
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§inde, eksik ΓΌst klasΓΆrler dahil bir klasΓΆr oluΕturur.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean: klasΓΆr sonrasΔ±nda varsa true. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
if (window.WebToApkFS && window.WebToApkFS.hasAccess()) {
var month = new Date().toISOString().slice(0, 7); // "2026-06"
if (window.WebToApkFS.mkdir('journal/' + month)) {
window.WebToApkFS.writeText('journal/' + month + '/readme.txt', 'One file per day.');
} else {
alert('Could not create the folder.');
}
}Ilk kullanΔ±mda bir projenin klasΓΆr dΓΌzenini kurun ve oluΕturulamayan klasΓΆrleri bildirin:
function createProjectFolders(project) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return false;
var failed = ['images', 'exports', 'drafts'].filter(function (sub) {
return !window.WebToApkFS.mkdir('projects/' + project + '/' + sub);
});
if (failed.length) alert('Could not create: ' + failed.join(', '));
return failed.length === 0;
}
createProjectFolders('holiday-2026');Ad zaten kullanΔ±lΔ±yorsa uyaran bir "Yeni klasΓΆr" dΓΌΔmesi (Γ§ΓΌnkΓΌ mkdir mevcut bir klasΓΆr iΓ§in true dΓΆndΓΌrΓΌr):
document.getElementById('new-folder').addEventListener('click', function () {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return;
var name = (prompt('Folder name') || '').trim();
if (!name || /[\\/]/.test(name) || name === '.' || name === '..') return;
var taken = window.WebToApkFS.list('').some(function (e) { return e.name === name; });
if (taken) { alert('"' + name + '" already exists.'); return; }
if (window.WebToApkFS.mkdir(name)) renderFolder(''); // your app: refresh the list
else alert('Could not create "' + name + '".');
});Notlar: KlasΓΆr zaten varsa true dΓΆner; bu yΓΌzden her kayΔ±ttan ΓΆnce Γ§aΔΔ±rmak sorun deΔildir. AynΔ± adlΔ± bir DOSYA yoldaysa, yol .. iΓ§eriyorsa veya hiΓ§ klasΓΆr verilmemiΕse false dΓΆner. WebToApkFS.writeText() eksik ΓΌst klasΓΆrleri zaten oluΕturur; bu yΓΌzden mkdir yalnΔ±zca boΕ klasΓΆrler iΓ§in gerekir.
WebToApkFS.readText yardımcı#
WebToApkFS.readText(relativePath)
Örnek
Δ°zin verilen klasΓΆrdeki bir metin dosyasΔ±nΔ± UTF-8 olarak okur.
DΓΆner deΔer: eΕzamanlΔ± olarak bir dize: dosyanΔ±n metni veya ''. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
'' "boΕ dosya" VEYA "dosya yok" anlamΔ±na gelir. Hangisi olduΔunu bilmeniz gerekiyorsa WebToApkFS.stat() kullanΔ±n:
function loadSettings() {
if (!window.WebToApkFS) return null;
var info = window.WebToApkFS.stat('data/settings.json');
if (!info.ok) return null; // not saved yet
try {
return JSON.parse(window.WebToApkFS.readText('data/settings.json'));
} catch (e) {
alert('settings.json is damaged: ' + e.message);
return null;
}
}Bir notu metin kutusuna aΓ§Δ±n:
if (window.WebToApkFS && window.WebToApkFS.hasAccess()) {
document.getElementById('editor').value = window.WebToApkFS.readText('notes/today.txt');
}KullanΔ±cΔ±nΔ±n klasΓΆre bΔ±raktΔ±ΔΔ± bir CSV'yi iΓ§e aktarΔ±n:
function importCsv(path) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return [];
var text = window.WebToApkFS.readText(path);
if (!text) return []; // missing or empty
var lines = text.replace(/\r/g, '').split('\n').filter(Boolean);
var header = lines.shift().split(',');
return lines.map(function (line) {
var cells = line.split(',');
var row = {};
header.forEach(function (h, i) { row[h.trim()] = (cells[i] || '').trim(); });
return row;
});
}
var contacts = importCsv('import/contacts.csv');
console.log(contacts.length + ' rows imported');Notlar: DosyanΔ±n tamamΔ± bir anda yΓΌklenir; bΓΌyΓΌk veya ikili dosyalar iΓ§in WebToApkFS.readBytes() kullanΔ±n. GeΓ§erli UTF-8 olmayan baytlar deΔiΕtirme karakteri olarak gelir. Bir klasΓΆr, .. iΓ§eren bir yol veya izin verilmiΕ klasΓΆr olmamasΔ± da Εunu dΓΆndΓΌrΓΌr: ''.
WebToApkFS.rename yardımcı#
WebToApkFS.rename(relativePath, newName)
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§indeki bir dosyayΔ± veya klasΓΆrΓΌ yeniden adlandΔ±rΔ±r.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
newName bir yol deΔil, yalnΔ±zca yeni addΔ±r. Girdi aynΔ± klasΓΆrde kalΔ±r:
function renameNote(path, newName) {
if (!window.WebToApkFS) return false;
var ok = window.WebToApkFS.rename(path, newName); // 'notes/a.txt', 'b.txt' -> notes/b.txt
if (!ok) alert('Could not rename. A file called "' + newName + '" may already exist.');
return ok;
}
renameNote('notes/today.txt', 'journal.txt');
renameNote('notes/2025', 'archive-2025'); // folders work tooΓakmadan yeniden adlandΔ±rΔ±n: boΕ bir ad bulunana kadar "ad (2)", "ad (3)" β¦ deneyin:
function renameUnique(path, wanted) {
if (!window.WebToApkFS) return '';
var dot = wanted.lastIndexOf('.');
var base = dot > 0 ? wanted.slice(0, dot) : wanted;
var ext = dot > 0 ? wanted.slice(dot) : '';
for (var n = 1; n <= 20; n++) {
var name = n === 1 ? wanted : base + ' (' + n + ')' + ext;
if (window.WebToApkFS.rename(path, name)) return name;
}
return '';
}
var finalName = renameUnique('photos/IMG_0042.jpg', 'Beach.jpg');GΓΌvenle kaydedin: ΓΆnce geΓ§ici bir dosya yazΔ±n, sonra yerine koyun (yeniden adlandΔ±rma alΔ±nmΔ±Ε bir adΔ± reddeder; bu yΓΌzden eski dosya hemen ΓΆncesinde silinir):
function saveSafely(folder, name, text) {
var fs = window.WebToApkFS;
if (!fs || !fs.hasAccess()) return false;
var tmp = folder + '/' + name + '.tmp';
if (!fs.writeText(tmp, text)) return false; // the original is untouched
fs.delete(folder + '/' + name); // false when it did not exist yet
return fs.rename(tmp, name);
}
saveSafely('notes', 'today.txt', document.getElementById('editor').value);Notlar: BaΕka bir girdi zaten newName adΔ±na sahipse, newName boΕsa, ./.. ise ya da / veya \ iΓ§eriyorsa, yol yoksa ya da izin verilmiΕ klasΓΆr yoksa false dΓΆner. Bir dosyayΔ± klasΓΆrler arasΔ±nda taΕΔ±mak iΓ§in onu okuyun, yeni yere yazΔ±n, sonra eskisini silin.
WebToApkFS.requestAccess yardımcı#
WebToApkFS.requestAccess()
Örnek
KullanΔ±cΔ±nΔ±n uygulamaya, yeniden baΕlatmalarda korunan bir klasΓΆr verebilmesi iΓ§in sistem klasΓΆr seΓ§icisini aΓ§ar.
DΓΆner deΔer: her zaman Γ§ΓΆzΓΌlen (asla reddedilmeyen) bir Promise: { success, folderUri, requestId }, ve success false olduΔunda ayrΔ±ca error. success bir boolean'dΔ±r; folderUri, izin verilen content://…/tree/… adresi ya da ''. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin.
KullanΔ±cΔ±nΔ±n dokunduΔu bir dΓΌΔmeden isteyin ve hangi klasΓΆrΓΌn baΔlΔ± olduΔunu gΓΆsterin:
document.getElementById('choose-folder').addEventListener('click', async function () {
if (!window.WebToApkFS) {
alert('Folder access is not available in this app.');
return;
}
var r = await window.WebToApkFS.requestAccess();
if (!r.success) {
document.getElementById('status').textContent = 'No folder chosen.';
return;
}
var name = decodeURIComponent(r.folderUri.split('/tree/')[1] || '').split(':').pop();
document.getElementById('status').textContent = 'Saving to: ' + name;
window.WebToApkFS.writeText('hello.txt', 'Connected at ' + new Date().toISOString());
});YalnΔ±zca henΓΌz izin verilmiΕ bir klasΓΆr yoksa isteyin:
async function ensureFolder() {
if (!window.WebToApkFS) return false;
if (window.WebToApkFS.hasAccess()) return true;
var r = await window.WebToApkFS.requestAccess();
return r.success;
}Δ°steΔin baΕarΔ±sΔ±z olabileceΔi her yolu aΓ§Δ±klayan bir "KlasΓΆrΓΌ deΔiΕtir" dΓΌΔmesi:
var folderErrors = {
cancelled: 'No folder chosen.',
busy: 'The folder picker is already open.',
not_persisted: 'Android would not keep access to that folder. Try another one.',
disabled: 'Folder access is switched off in this app.',
no_picker: 'This phone has no folder picker.',
foreign_origin: 'This page is not allowed to use folders.'
};
document.getElementById('change-folder').addEventListener('click', async function () {
if (!window.WebToApkFS) return;
var r = await window.WebToApkFS.requestAccess();
document.getElementById('status').textContent = r.success
? 'Folder changed.'
: (folderErrors[r.error] || 'Could not open the folder picker.');
if (r.success) renderFolder(''); // your app: show the new folder
});Notlar: SayfanΔ±n yΓΌklenmesinde deΔil, bir dokunuΕtan Γ§aΔΔ±rΔ±n; seΓ§ici uygulamayΔ± kaplar. success: false, error ile gelir: 'cancelled' (kullanΔ±cΔ± vazgeΓ§ti), 'not_persisted' (Android izni korumadΔ±), 'disabled', 'busy' (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), 'no_picker' veya 'foreign_origin'. Yeniden seΓ§mek ΓΆnceki klasΓΆrΓΌn yerini alΔ±r.
WebToApkFS.writeText yardımcı#
WebToApkFS.writeText(relativePath, content)
Örnek
Δ°zin verilen klasΓΆre UTF-8 bir metin dosyasΔ± yazar; dosyayΔ± (ve eksik ΓΌst klasΓΆrleri) oluΕturur veya ΓΌzerine yazar.
DΓΆner deΔer: eΕzamanlΔ± olarak bir boolean: dosya yazΔ±ldΔ±ysa true. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin ve izin verilmiΕ bir klasΓΆr olsun.
Bir dΓΌΔmeden kaydedin:
document.getElementById('save').addEventListener('click', async function () {
if (!window.WebToApkFS) { alert('Saving to a folder is not available here.'); return; }
if (!window.WebToApkFS.hasAccess()) {
var r = await window.WebToApkFS.requestAccess();
if (!r.success) return; // user cancelled
}
var ok = window.WebToApkFS.writeText('notes/today.txt', document.getElementById('editor').value);
document.getElementById('status').textContent = ok ? 'Saved' : 'Could not save';
});Bir nesneyi JSON olarak kaydedin:
if (window.WebToApkFS && window.WebToApkFS.hasAccess()) {
window.WebToApkFS.writeText('data/settings.json', JSON.stringify({ theme: 'dark', size: 16 }, null, 2));
}GΓΌnlΓΌk bir kayΔ±da satΔ±r ekleyin (ekleme yoktur; bu yΓΌzden okuyun, ekleyin ve geri yazΔ±n):
function logLine(message) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return false;
var path = 'logs/' + new Date().toISOString().slice(0, 10) + '.log'; // one file per day
var old = window.WebToApkFS.readText(path);
var line = new Date().toLocaleTimeString() + ' ' + message + '\n';
return window.WebToApkFS.writeText(path, old + line);
}
logLine('Order #1042 marked as shipped');Notlar: Var olan bir dosyanΔ±n yerini tamamen alΔ±r; ekleme yoktur. content bir dizeye dΓΆnΓΌΕtΓΌrΓΌlΓΌr (null, '' olur). Yol var olan bir klasΓΆrse, .. iΓ§eriyorsa veya izin verilmiΕ klasΓΆr yoksa false dΓΆner. Dosya tΓΌrΓΌ uzantΔ±dan alΔ±nΔ±r; bu yΓΌzden diskteki ad tam olarak verdiΔiniz addΔ±r.
clearFolderAccess köprü#
window.WebToApk.clearFolderAccess()
KalΔ±cΔ± klasΓΆr iznini serbest bΔ±rakΔ±r. YabancΔ± bir sayfa iΓ§in reddedilir (iΕlem yapΔ±lmaz).
Örnek
Δ°zin verilen klasΓΆrΓΌ unutur ve izni Android'e geri verir.
DΓΆner deΔer: hiΓ§bir Εey (eΕzamanlΔ±). WebToApkFS.clearAccess() aynΔ±sΔ±nΔ± yapar. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli; anahtar kapalΔ±yken hiΓ§bir Εey yapmaz.
Bir "BaΔlantΔ±yΔ± kes" dΓΌΔmesi:
document.getElementById('disconnect').addEventListener('click', function () {
if (window.WebToApkFS) {
window.WebToApkFS.clearAccess();
} else if (window.WebToApk && typeof window.WebToApk.clearFolderAccess === 'function') {
window.WebToApk.clearFolderAccess();
}
document.getElementById('folder-name').textContent = 'No folder chosen';
});Γkis yaparken klasΓΆrΓΌ de unutun; bΓΆylece bu telefondaki bir sonraki kiΕi kendi klasΓΆrΓΌnΓΌ seΓ§er:
function signOut() {
localStorage.clear();
if (window.WebToApk && typeof window.WebToApk.clearFolderAccess === 'function') {
window.WebToApk.clearFolderAccess();
}
location.href = 'login.html';
}Dosyalar uygulamasΔ±nda taΕΔ±nmΔ±Ε veya silinmiΕ bir klasΓΆrΓΌ unutun, sonra yeniden seΓ§meyi teklif edin (uygulama bir klasΓΆr ilk baΔlandΔ±ΔΔ±nda myapp-folder.json yazar):
async function reconnectIfMissing() {
var fs = window.WebToApkFS;
if (!fs || !fs.hasAccess()) return;
if (fs.stat('myapp-folder.json').ok) return; // marker still there: the folder is fine
if (typeof window.WebToApk.clearFolderAccess === 'function') {
window.WebToApk.clearFolderAccess(); // drop the grant that points nowhere
}
if (confirm('The folder you chose earlier is gone. Choose a folder again?')) {
var r = await fs.requestAccess();
if (r.success) fs.writeText('myapp-folder.json', '{}');
}
}Notlar: KlasΓΆrdeki dosyalar SΔ°LΔ°NMEZ; uygulama yalnΔ±zca onlara artΔ±k ulaΕamaz. Bundan sonra hasFolderAccess(), "false" yanΔ±tΔ±nΔ± verir ve kullanΔ±cΔ± yeniden bir klasΓΆr seΓ§ene kadar her dosya yΓΆntemi baΕarΔ±sΔ±z olur.
deleteEntry köprü#
window.WebToApk.deleteEntry(relativePath: String, recursive: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§indeki bir dosyayΔ± veya klasΓΆrΓΌ siler.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ°. WebToApkFS.delete(path, { recursive }) gerΓ§ek bir boolean dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
YardΔ±mcΔ± ile, kullanΔ±cΔ±ya sorduktan sonra:
function removeEntry(path, isFolder) {
if (!window.WebToApkFS) return false;
if (!confirm('Delete ' + path + '? This cannot be undone.')) return false;
return window.WebToApkFS.delete(path, { recursive: isFolder });
}
removeEntry('notes/old.txt', false);
removeEntry('notes/2025', true); // the folder and everything in itHam Γ§aΔrΔ±: ikinci argΓΌman 'true' DΔ°ZESΔ°DΔ°R ya da 'false':
if (window.WebToApk && typeof window.WebToApk.deleteEntry === 'function') {
var gone = window.WebToApk.deleteEntry('cache', 'true') === 'true';
}YalnΔ±zca en yeni beΕ yedeΔi tutun ve gerisini silin:
function pruneBackups(keep) {
var fs = window.WebToApkFS;
if (!fs) return 0;
var files = fs.list('backups').filter(function (e) { return !e.isDirectory; });
files.sort(function (a, b) { return b.lastModified - a.lastModified; }); // newest first
var removed = 0;
files.slice(keep).forEach(function (e) {
if (fs.delete('backups/' + e.name)) removed++;
});
return removed;
}
console.log(pruneBackups(5) + ' old backups deleted');Notlar: BoΕ olmayan bir klasΓΆr yalnΔ±zca 'true' ΓΆzyinelemeli ile silinir. Δ°zin verilen klasΓΆrΓΌn kendisi ('') asla silinemez. Silme gerΓ§ek ve anΔ±ndadΔ±r: Γ§ΓΆp kutusu yoktur.
getFolderAccessUri köprü#
window.WebToApk.getFolderAccessUri(): String
Δ°zin verilen klasΓΆrΓΌn `content://` aΔaΓ§ URI'si ya da "" (yok, devre dΔ±ΕΔ± veya yabancΔ± bir sayfa).
Örnek
KullanΔ±cΔ±nΔ±n izin verdiΔi klasΓΆrΓΌn adresini verir; bΓΆylece hangi klasΓΆrΓΌn baΔlΔ± olduΔunu gΓΆsterebilirsiniz.
DΓΆner deΔer: eΕzamanlΔ± olarak bir dize: content://com.android.externalstorage.documents/tree/primary%3ADocuments%2FNotes gibi bir aΔaΓ§ URI'si ya da izin verilmiΕ klasΓΆr yoksa veya anahtar kapalΔ±ysa "". WebToApkFS.getAccessUri() aynΔ± dizeyi dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli.
URI'yi kullanΔ±cΔ±nΔ±n tanΔ±yacaΔΔ± bir ada dΓΆnΓΌΕtΓΌrΓΌn:
function folderLabel() {
var uri = '';
if (window.WebToApkFS) {
uri = window.WebToApkFS.getAccessUri();
} else if (window.WebToApk && typeof window.WebToApk.getFolderAccessUri === 'function') {
uri = window.WebToApk.getFolderAccessUri();
}
if (!uri) return '';
var tail = uri.split('/tree/')[1] || '';
try { tail = decodeURIComponent(tail); } catch (e) {}
return tail.split(':').pop() || tail; // "primary:Documents/Notes" -> "Documents/Notes"
}
var label = folderLabel();
document.getElementById('folder-name').textContent = label ? 'Saving to: ' + label : 'No folder chosen';Dosya listesini yalnΔ±zca kullanΔ±cΔ± gerΓ§ekten farklΔ± bir klasΓΆr seΓ§tiΔinde yeniden yΓΌkleyin:
document.getElementById('change-folder').addEventListener('click', async function () {
if (!window.WebToApkFS) return;
var before = window.WebToApkFS.getAccessUri();
var r = await window.WebToApkFS.requestAccess();
if (!r.success) return; // the old folder is still connected
if (r.folderUri !== before) {
renderFiles(window.WebToApkFS.list('')); // a new place: show what is in it
}
});KlasΓΆrΓΌn telefonda, bir SD kartta veya baΕka bir depolama uygulamasΔ±nda olup olmadΔ±ΔΔ±nΔ± sΓΆyleyin:
function folderLocation() {
var uri = window.WebToApkFS ? window.WebToApkFS.getAccessUri() : '';
if (!uri) return 'none';
var id = uri.split('/tree/')[1] || '';
try { id = decodeURIComponent(id); } catch (e) {}
if (uri.indexOf('com.android.externalstorage.documents') === -1) return 'other'; // e.g. a cloud drive app
return id.indexOf('primary:') === 0 ? 'phone' : 'sd-card'; // "1A2B-3C4D:Music" is a card
}
document.getElementById('folder-where').textContent =
{ none: '', phone: 'Phone storage', 'sd-card': 'SD card', other: 'Another storage app' }[folderLocation()];Notlar: Bu URI'yi dosya yΓΆntemlerine asla geri vermezsiniz; hepsi bu klasΓΆre gΓΆre gΓΆreli yollar alΔ±r. AdΔ±, dosyalarΔ±n nereye gittiΔini kullanΔ±cΔ±nΔ±n bilmesi iΓ§in bir "BaΔlantΔ±yΔ± kes" dΓΌΔmesinin yanΔ±nda gΓΆsterin.
hasFolderAccess köprü#
window.WebToApk.hasFolderAccess(): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
KullanΔ±cΔ±nΔ±n uygulamaya zaten bir klasΓΆr verip vermediΔini sΓΆyler.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ° (boolean deΔil). WebToApkFS.hasAccess() gerΓ§ek bir boolean verir. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli; bu olmadan yanΔ±t her zaman "false".
Ham yΓΆntem sayfanΔ±n ilk satΔ±rΔ±ndan itibaren vardΔ±r; bu yΓΌzden sayfa hΓ’lΓ’ yΓΌklenirken doΔru kontroldΓΌr (WebToApkFS yalnΔ±zca yΓΌkleme bittiΔinde eklenir):
function folderConnected() {
if (window.WebToApkFS) return window.WebToApkFS.hasAccess();
return !!(window.WebToApk && typeof window.WebToApk.hasFolderAccess === 'function' &&
window.WebToApk.hasFolderAccess() === 'true');
}
document.getElementById('choose-folder').hidden = folderConnected();Bir kayΔ±ttan ΓΆnce kontrol edin ve yalnΔ±zca henΓΌz baΔlΔ± bir klasΓΆr yoksa seΓ§iciyi aΓ§Δ±n:
async function saveBackup(json) {
if (!window.WebToApkFS) return false;
if (!window.WebToApkFS.hasAccess()) {
var r = await window.WebToApkFS.requestAccess(); // asked once; the grant is remembered
if (!r.success) return false;
}
return window.WebToApkFS.writeText('backup.json', json);
}
document.getElementById('backup').addEventListener('click', function () {
saveBackup(JSON.stringify(appState));
});YalnΔ±zca bir klasΓΆr baΔlΔ±yken yazan ve seΓ§iciyi asla kendisi aΓ§mayan bir otomatik kayΔ±t zamanlayΔ±cΔ±sΔ±:
setInterval(function () {
if (!window.WebToApk || typeof window.WebToApk.hasFolderAccess !== 'function') return;
if (window.WebToApk.hasFolderAccess() !== 'true') return; // not connected: the Save button asks
window.WebToApk.writeTextFile('drafts/autosave.txt', document.getElementById('editor').value);
}, 30000);Notlar: === 'true' ile karΕΔ±laΕtΔ±rΔ±n; "false" dizesi doΔru kabul edilir. YalnΔ±zca uygulamanΔ±n bir klasΓΆrΓΌ hatΔ±rladΔ±ΔΔ±nΔ± sΓΆyler. O klasΓΆr Dosyalar uygulamasΔ±nda silinmiΕ veya taΕΔ±nmΔ±Εsa listFolderEntries(''), [] dΓΆner; kullanΔ±cΔ±dan yeniden seΓ§mesini isteyin.
isFolderAccessEnabled köprü#
window.WebToApk.isFolderAccessEnabled(): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Bu uygulamanΔ±n klasΓΆr eriΕimi aΓ§Δ±k olarak derlenip derlenmediΔini sΓΆyler.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ°. Gerekenler: Γ§aΔΔ±rmak iΓ§in bir Εey yok; yalnΔ±zca AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretlendiyse "true" yanΔ±tΔ±nΔ± verir.
KlasΓΆr ΓΆzelliΔini gΓΆsterip gΓΆstermeyeceΔinize karar vermek iΓ§in kullanΔ±n. WebToApkFS.isAvailable() sayfa yΓΌklendikten sonra aynΔ± soruyu boolean olarak yanΔ±tlar:
function folderFeatureShipped() {
if (window.WebToApkFS) return window.WebToApkFS.isAvailable();
return !!(window.WebToApk && typeof window.WebToApk.isFolderAccessEnabled === 'function' &&
window.WebToApk.isFolderAccessEnabled() === 'true');
}
if (!folderFeatureShipped()) {
document.getElementById('folder-panel').hidden = true; // in a browser, or the switch was off
}Bir ayarlar satΔ±rΔ±nΔ± ΓΌΓ§ durumuyla yΓΆnetin (bu derlemede yok, baΔlΔ± deΔil, baΔlΔ±):
function folderSettingsState() {
var fs = window.WebToApkFS;
if (!fs || !fs.isAvailable()) return 'unavailable';
return fs.hasAccess() ? 'connected' : 'not-connected';
}
var row = document.getElementById('folder-row');
switch (folderSettingsState()) {
case 'unavailable': row.hidden = true; break;
case 'not-connected': row.querySelector('button').textContent = 'Choose a folder'; break;
case 'connected': row.querySelector('button').textContent = 'Disconnect'; break;
}SayfayΔ± Γ§izilmeden ΓΆnce iΕaretleyin; bΓΆylece CSS yalnΔ±zca klasΓΆre ΓΆzgΓΌ denetimleri titremeden gΓΆsterebilir:
// In a <script> inside <head>: the raw method is already there.
if (window.WebToApk && typeof window.WebToApk.isFolderAccessEnabled === 'function' &&
window.WebToApk.isFolderAccessEnabled() === 'true') {
document.documentElement.classList.add('has-folders'); // .has-folders .folder-only { display: block }
}Notlar: Bu, henΓΌz bir klasΓΆr seΓ§ilip seΓ§ilmediΔi hakkΔ±nda bir Εey sΓΆylemez; bunun iΓ§in hasFolderAccess() kullanΔ±n. Bir tarayΔ±cΔ±da window.WebToApk yoktur; bu yΓΌzden yukarΔ±daki kontrol hata vermeden false yanΔ±tΔ±nΔ± verir.
listFolderEntries köprü#
window.WebToApk.listFolderEntries(relativePath: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆrΓΌn bir klasΓΆrΓΌndeki dosyalarΔ± ve alt klasΓΆrleri listeler.
DΓΆner deΔer: eΕzamanlΔ± olarak bir JSON DΔ°ZESΔ°: { name, uri, isDirectory, length, lastModified } dizisi (length bayt cinsinden, lastModified 1970'ten beri ms cinsinden). WebToApkFS.list(path) onu sizin iΓ§in ayrΔ±ΕtΔ±rΔ±r. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
YardΔ±mcΔ± ile ('' izin verilen klasΓΆrΓΌn kendisidir):
function showFolder(path) {
if (!window.WebToApkFS) return;
var entries = window.WebToApkFS.list(path); // already an array
entries.forEach(function (e) {
console.log(e.isDirectory ? '[dir] ' : ' ', e.name, e.length + ' bytes');
});
}
showFolder(''); // the root
showFolder('notes'); // a sub-folderAyrΔ±ΕtΔ±rmanΔ±z gereken metin dΓΆndΓΌren ham Γ§aΔrΔ±:
if (window.WebToApk && typeof window.WebToApk.listFolderEntries === 'function') {
var entries = JSON.parse(window.WebToApk.listFolderEntries('notes'));
console.log(entries.length + ' entries');
}En yeni yedek dosyasΔ±nΔ± bulun ve ne zaman yapΔ±ldΔ±ΔΔ±nΔ± gΓΆsterin:
function latestBackup() {
if (!window.WebToApkFS) return null;
var backups = window.WebToApkFS.list('backups').filter(function (e) {
return !e.isDirectory && /\.json$/i.test(e.name);
});
backups.sort(function (a, b) { return b.lastModified - a.lastModified; }); // newest first
return backups[0] || null;
}
var last = latestBackup();
document.getElementById('last-backup').textContent =
last ? 'Last backup: ' + new Date(last.lastModified).toLocaleString() : 'No backups yet';Notlar: BoΕ bir klasΓΆr, eksik bir klasΓΆr, dosya olan bir yol, .. iΓ§eren bir yol, izin verilmiΕ klasΓΆrΓΌn olmamasΔ± ve yabancΔ± bir web sitesinden gelen sayfa hepsi [] yanΔ±tΔ±nΔ± verir; "klasΓΆr yok" durumunu ayΔ±rt etmeniz gerekiyorsa ΓΆnce hasFolderAccess() Γ§aΔrΔ±n. Yollar gΓΆrelidir, / kullanΔ±r ve izin verilen klasΓΆrΓΌn ΓΌstΓΌne asla Γ§Δ±kmaz.
mkdir köprü#
window.WebToApk.mkdir(relativePath: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§inde, eksik ΓΌst klasΓΆrler dahil bir klasΓΆr oluΕturur.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ°. WebToApkFS.mkdir(path) gerΓ§ek bir boolean dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
YardΔ±mcΔ± ile:
if (window.WebToApkFS && window.WebToApkFS.hasAccess()) {
var ok = window.WebToApkFS.mkdir('photos/2026/june'); // creates photos, 2026 and june
if (!ok) console.log('Could not create the folder');
}Ham çağrı:
if (window.WebToApk && typeof window.WebToApk.mkdir === 'function') {
var made = window.WebToApk.mkdir('backups') === 'true';
}Bir dΔ±Εa aktarma iΓ§in tarihli bir klasΓΆr oluΕturun ve her ΓΆΔeyi iΓ§ine yazΔ±n:
function exportAll(items) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return false;
var dir = 'exports/' + new Date().toISOString().slice(0, 10); // e.g. exports/2026-09-25
if (!window.WebToApkFS.mkdir(dir)) {
alert('Could not create ' + dir + ' (is a file with that name in the way?)');
return false;
}
items.forEach(function (item) {
window.WebToApkFS.writeText(dir + '/' + item.id + '.json', JSON.stringify(item));
});
return true;
}Notlar: KlasΓΆr zaten varsa "true" dΓΆner; bu yΓΌzden her kayΔ±ttan ΓΆnce Γ§aΔrΔ±lmasΔ± gΓΌvenlidir. AynΔ± adlΔ± bir DOSYA yoldaysa, yol .. iΓ§eriyorsa veya hiΓ§ klasΓΆr verilmemiΕse "false" dΓΆner.
readTextFile köprü#
window.WebToApk.readTextFile(relativePath: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆrdeki bir metin dosyasΔ±nΔ± UTF-8 olarak okur.
DΓΆner deΔer: eΕzamanlΔ± olarak bir dize: dosyanΔ±n metni veya "". WebToApkFS.readText(path) aynΔ±sΔ±nΔ± dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
"" "boΕ dosya" VEYA "dosya yok" anlamΔ±na gelir; bu yΓΌzden fark ΓΆnemliyse WebToApkFS.stat() ile kontrol edin:
function loadNote(path) {
if (!window.WebToApkFS) return null;
var info = window.WebToApkFS.stat(path); // { ok: true, name, size, ... } or { ok: false, error: 'not-found' }
if (!info.ok) return null; // the file does not exist
return window.WebToApkFS.readText(path); // '' here really is an empty file
}
var text = loadNote('notes/today.txt');
document.getElementById('editor').value = text === null ? '' : text;Ham çağrı:
if (window.WebToApk && typeof window.WebToApk.readTextFile === 'function') {
var raw = window.WebToApk.readTextFile('notes/today.txt');
console.log(raw.length + ' characters');
}Bir klasΓΆrdeki her .txt ve .md notunu iΓ§e aktarΔ±n:
function importNotes(folder) {
if (!window.WebToApkFS) return [];
return window.WebToApkFS.list(folder)
.filter(function (e) { return !e.isDirectory && /\.(txt|md)$/i.test(e.name); })
.map(function (e) {
return {
title: e.name.replace(/\.(txt|md)$/i, ''),
body: window.WebToApkFS.readText(folder + '/' + e.name)
};
});
}
renderNotes(importNotes('notes'));Notlar: DosyanΔ±n tamamΔ± belleΔe okunur; notlar ve JSON iΓ§in uygundur, bΓΌyΓΌk dosyalar iΓ§in deΔil; onlar iΓ§in WebToApkFS.readBytes kullanΔ±n. GeΓ§erli UTF-8 olmayan baytlar deΔiΕtirme karakteri olarak gelir. Bir klasΓΆr yolu, .. iΓ§eren bir yol, izin verilmiΕ klasΓΆrΓΌn olmamasΔ± veya yabancΔ± bir web sitesinden gelen sayfa hepsi Εunu yanΔ±tlar: "".
renameEntry köprü#
window.WebToApk.renameEntry(relativePath: String, newName: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆrΓΌn iΓ§indeki bir dosyayΔ± veya klasΓΆrΓΌ yeniden adlandΔ±rΔ±r.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ°. WebToApkFS.rename(path, newName) gerΓ§ek bir boolean dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
newName dГјz bir addΔ±r, yol deΔil; girdi aynΔ± klasΓΆrde kalΔ±r:
if (window.WebToApkFS) {
var ok = window.WebToApkFS.rename('notes/today.txt', 'journal.txt'); // -> notes/journal.txt
if (!ok) alert('Rename failed. Is there already a file called journal.txt?');
}Ham çağrı:
if (window.WebToApk && typeof window.WebToApk.renameEntry === 'function') {
var renamed = window.WebToApk.renameEntry('old-folder', 'new-folder') === 'true';
}Yeni yedek yazΔ±lmadan ΓΆnce ΓΆnceki yedeΔi yeniden adlandΔ±rarak koruyun:
function rotateBackup(json) {
var fs = window.WebToApkFS;
if (!fs || !fs.hasAccess()) return false;
if (fs.stat('backup.json').ok) {
var stamp = new Date().toISOString().replace(/[:.]/g, '-'); // no characters a file name cannot hold
fs.rename('backup.json', 'backup-' + stamp + '.json'); // stays in the same folder
}
return fs.writeText('backup.json', json);
}Notlar: BaΕka bir girdi zaten newName adΔ±na sahipse, newName boΕsa ya da / veya \ iΓ§eriyorsa, yol yoksa ya da izin verilmiΕ klasΓΆr yoksa baΕarΔ±sΔ±z olur. Bir dosyayΔ± baΕka bir klasΓΆre taΕΔ±mak iΓ§in oraya yazΔ±n ve eskisini silin.
requestFolderAccess köprü#
window.WebToApk.requestFolderAccess(requestId: String)
Sistem klasΓΆr seΓ§icisini aΓ§ar ve seΓ§ilen klasΓΆre okuma/yazma eriΕimini kalΔ±cΔ± kΔ±lar. YanΔ±t `WebToApkOnFolderAccessResult` ΓΌzerinden gelir; aynΔ± anda yalnΔ±zca bir seΓ§ici aΓ§Δ±k olabilir, bu yΓΌzden biri aΓ§Δ±kken yapΔ±lan bir istek hemen `error:"busy"` ile yanΔ±tlanΔ±r ve aΓ§Δ±k olan kendi yanΔ±tΔ±nΔ± korur.
Örnek
KullanΔ±cΔ±nΔ±n uygulamaya bir klasΓΆr verebilmesi iΓ§in sistem klasΓΆr seΓ§icisini aΓ§ar. Sayfalar normalde bu Γ§aΔrΔ±yΔ± bir Promise iΓ§ine saran WebToApkFS.requestAccess() kullanΔ±r.
DΓΆner deΔer: hiΓ§bir Εey. YanΔ±t, WebToApkFS tarafΔ±ndan yΓΆnetilen dahili bir geri Γ§aΔrΔ±yla sonra gelir; WebToApkFS.requestAccess(), { success, folderUri, requestId } ile Γ§ΓΆzΓΌlΓΌr ve success false olduΔunda ayrΔ±ca error iΓ§erir. Gerekenler: derleme yaparken AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) kutusunu iΕaretleyin.
YardΔ±mcΔ± ile bir dΓΌΔme dokunuΕundan isteyin:
document.getElementById('choose-folder').addEventListener('click', async function () {
if (!window.WebToApkFS) {
alert('Folder access is not available in this app.');
return;
}
var r = await window.WebToApkFS.requestAccess();
if (r.success) {
console.log('Folder granted:', r.folderUri); // content://.../tree/...
} else {
console.log('No folder chosen'); // user cancelled, or Android refused the grant
}
});YalnΔ±zca ilk seferde isteyin, sonra uygulamanΔ±n kendi alt klasΓΆrΓΌnΓΌ kurun:
async function ensureFolder() {
if (!window.WebToApkFS || !window.WebToApkFS.isAvailable()) return false;
if (window.WebToApkFS.hasAccess()) return true; // granted on an earlier run
var r = await window.WebToApkFS.requestAccess();
if (!r.success) return false;
window.WebToApkFS.mkdir('exports'); // true even if it already exists
return true;
}
document.getElementById('export').addEventListener('click', async function () {
if (!(await ensureFolder())) return;
window.WebToApkFS.writeText('exports/list.csv', buildCsv());
});GerΓ§ek error kodlarΔ±nΔ± kullanarak kullanΔ±cΔ±ya neden bir klasΓΆr baΔlanmadΔ±ΔΔ±nΔ± tam olarak sΓΆyleyin:
var folderMessages = {
cancelled: 'No folder was chosen.',
not_persisted: 'Android would not keep access to that folder. Please choose another one.',
busy: 'The folder picker is already open.',
disabled: 'This app was built without folder access.',
foreign_origin: 'A folder can only be connected from the app\'s own pages.',
no_picker: 'This phone has no folder picker.'
};
document.getElementById('choose-folder').addEventListener('click', async function () {
if (!window.WebToApkFS) return;
var r = await window.WebToApkFS.requestAccess();
document.getElementById('status').textContent = r.success
? 'Folder connected.'
: (folderMessages[r.error] || 'Could not connect a folder.');
});Notlar: Ham yΓΆntemi kendiniz Γ§aΔΔ±rmayΔ±n: tek yanΔ±tΔ± yardΔ±mcΔ±nΔ±n dinlediΔi geri Γ§aΔrΔ±dΔ±r. success, kullanΔ±cΔ± vazgeΓ§tiΔinde (error:'cancelled'), Android izni korumadΔ±ΔΔ±nda ('not_persisted') ve derleme anahtarΔ± aΓ§mamΔ±Εsa ('disabled') ya da ekrandaki sayfa uygulamanΔ±n kendisi deΔilse ('foreign_origin') hemen false olur. Δ°zin uygulama yeniden baΕlatΔ±lΔ±nca da korunur; yeniden seΓ§mek klasΓΆrΓΌn yerini alΔ±r. AynΔ± anda yalnΔ±zca bir seΓ§ici aΓ§Δ±k olabilir; biri aΓ§Δ±kken yapΔ±lan bir istek hemen error:'busy' ile yanΔ±tlanΔ±r ve aΓ§Δ±k olan kendi yanΔ±tΔ±nΔ± korur.
writeTextFile köprü#
window.WebToApk.writeTextFile(relativePath: String, content: String): String
KalΔ±cΔ± URI izinleriyle ACTION_OPEN_DOCUMENT_TREE kullanan, Play'e uygun klasΓΆr eriΕimi. JavaScript kullanΔ±mΔ±: window.WebToApk.requestFolderAccess('myRequestId') window.WebToApk.hasFolderAccess() // "true" / "false" window.WebToApk.getFolderAccessUri() // "content://..." veya "" window.WebToApk.clearFolderAccess() // kalΔ±cΔ± eriΕimi serbest bΔ±rakΔ±r Android β JS geri Γ§aΔrΔ±sΔ±: window.WebToApkOnFolderAccessResult(success, folderUri, requestId, error) `error` (4. argΓΌman, baΕarΔ±da "") bir isteΔin neden baΕarΔ±sΔ±z olduΔunu sΓΆyler: "disabled", "foreign_origin", "busy" (ΓΆnceki bir istek iΓ§in zaten bir seΓ§ici aΓ§Δ±k; o hΓ’lΓ’ kendi yanΔ±tΔ±nΔ± alΔ±r), "cancelled", "not_persisted", "no_picker".
Kendi baΕΔ±na deΔil, grubuyla birlikte anlatΔ±lΔ±r: Yerel KlasΓΆr EriΕimi (SAF) KΓΆprΓΌsΓΌ.
Örnek
Δ°zin verilen klasΓΆre bir metin dosyasΔ± (UTF-8) yazar; dosyayΔ± oluΕturur veya iΓ§eriΔini deΔiΕtirir.
DΓΆner deΔer: eΕzamanlΔ± olarak "true" veya "false" DΔ°ZESΔ°. WebToApkFS.writeText(path, text) gerΓ§ek bir boolean dΓΆndΓΌrΓΌr. Gerekenler: AdΔ±m 4'te (EriΕim) Yerel KlasΓΆr EriΕimi (SAF) iΕaretli ve izin verilmiΕ bir klasΓΆr.
YardΔ±mcΔ± ile:
function saveNote(path, text) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) {
alert('Choose a folder first.');
return false;
}
var ok = window.WebToApkFS.writeText(path, text); // missing parent folders are created
if (!ok) alert('Could not save ' + path);
return ok;
}
saveNote('notes/2026/today.txt', document.getElementById('editor').value);YanΔ±tΔ± metin olan ham Γ§aΔrΔ±:
if (window.WebToApk && typeof window.WebToApk.writeTextFile === 'function') {
var saved = window.WebToApk.writeTextFile('data/settings.json', JSON.stringify({ theme: 'dark' })) === 'true';
}GΓΌnlΓΌk bir kayΔ±da satΔ±r ekleyin: yazmak dosyanΔ±n yerini aldΔ±ΔΔ± iΓ§in ΓΆnce okuyun:
function appendLog(line) {
if (!window.WebToApkFS || !window.WebToApkFS.hasAccess()) return false;
var now = new Date().toISOString();
var path = 'logs/' + now.slice(0, 10) + '.log'; // one file per day
var old = window.WebToApkFS.readText(path); // '' the first time
return window.WebToApkFS.writeText(path, old + now + ' ' + line + '\n');
}
appendLog('Order #1042 marked as shipped');Notlar: Var olan bir dosyanΔ±n yerini tamamen alΔ±r. Yol var olan bir klasΓΆrse, .. iΓ§eriyorsa veya izin verilmiΕ klasΓΆr yoksa baΕarΔ±sΔ±z olur. Dosya tΓΌrΓΌ uzantΔ±dan alΔ±nΔ±r (.json, .txt, .mdβ¦); bu yΓΌzden verdiΔiniz ad diskteki addΔ±r.