JavaScript köprü API'si
Dosyalar: bu uygulamayla açılan
Başka bir uygulamanın "Birlikte aç" ile ilettiği şeyi, sayfanın çektiği parçalar halinde toplama.
AppMint.getOpenedFile yardımcı#
AppMint.getOpenedFile()
Örnek
Sayfanız ne kadar geç başlarsa başlasın, uygulamaya paylaşılan veya uygulamayla açılan ("Birlikte aç…") dosyayı sayfanıza verir.
Döndürür: Promise<object | null> - uygulama normal şekilde açıldığında null. Nesne token, name, mimeType, size, kind, url, file, getFile() içerir, ayrıca ucuzsa text (32 MB'a kadar metin dosyaları) veya base64 (8 MB'a kadar diğer veri dosyaları). kind, 'image' | 'video' | 'audio' | 'document' | 'data' olur. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın ve uygulamanızın kabul ettiği dosya türlerini işaretleyin.
async function handleStartFile() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return; // not in the app, or feature off
const f = await AppMint.getOpenedFile();
if (!f) return; // opened normally
console.log(f.name, f.mimeType, f.size, f.kind);
if (f.kind === 'video') {
document.querySelector('video').src = f.url; // streams from disk, can seek
} else if (f.kind === 'image') {
document.querySelector('img').src = f.url;
} else if (f.kind === 'document') {
const file = await f.getFile(); // a real File
await upload(file);
} else {
const text = typeof f.text === 'string' ? f.text : await f.file.text();
importData(text);
}
}
handleStartFile();Ya da dinleyin - olay (ve isteğe bağlı window.onAppMintFileOpen kancası) her yeni dosya için bir kez, şununla aynı nesneyle tetiklenir detail:
window.onAppMintFileOpen = function (f) { console.log('hook:', f.name); };
window.addEventListener('appmint:fileopen', function (e) {
const f = e.detail; // {token, name, mimeType, size, kind, url, file, getFile, text?, base64?}
showFile(f);
});
window.addEventListener('appmint:fileopenerror', function (e) {
alert('Could not read ' + e.detail.name + ': ' + e.detail.error); // detail: {name, error}
});Bir React uygulamasında küçük bir kanca, bileşen ne kadar geç bağlanırsa bağlansın dosyayı alır ve yenilerini izlemeye devam eder:
import { useEffect, useState } from 'react';
export function useOpenedFile() {
const [file, setFile] = useState(null);
useEffect(function () {
const A = window.AppMint;
if (!A || typeof A.getOpenedFile !== 'function') return;
let alive = true;
A.getOpenedFile().then(function (f) { if (alive && f) setFile(f); });
function onOpen(e) { setFile(e.detail); }
window.addEventListener('appmint:fileopen', onOpen);
return function () { alive = false; window.removeEventListener('appmint:fileopen', onOpen); };
}, []);
return file;
}Notlar: Resimler, videolar, ses ve 64 MB'ı aşan her dosya yalnızca url olarak gelir (file null olur); baytlara gerçekten ihtiyaç duyduğunuzda f.getFile() çağırın. Veri dosyaları ve belgeler de f.file olarak gelir. Dosya siz isteyene kadar sayfanız için tutulur; bu yüzden geç yüklenen bir SPA de onu alır; her seferinde en sonuncusu döndürülür. Uygulama zaten açıkken başka bir dosya geldiğinde olay yeniden tetiklenir. İşiniz bittiğinde önbellekteki kopyayı serbest bırakmak için AppMint.releaseOpenedFile(f) çağırın.
AppMint.getOpenedFiles yardımcı#
AppMint.getOpenedFiles()
Örnek
Bu oturum sırasında uygulamaya paylaşılan veya uygulamayla açılan her dosyayı sayfanıza verir - kullanıcı birkaç fotoğrafı aynı anda paylaştığında kullanışlıdır.
Döndürür: AppMint.getOpenedFile() işlevinin döndürdüğü aynı nesnelerin Promise<Array> değeri (token, name, mimeType, size, kind, url, file, getFile(), ucuzsa text / base64). Hiçbir şey alınmadıysa boş dizi. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın ve uygulamanızın kabul ettiği dosya türlerini işaretleyin.
async function importShared() {
if (!window.AppMint || typeof AppMint.getOpenedFiles !== 'function') return;
const files = await AppMint.getOpenedFiles();
const gallery = document.getElementById('gallery');
files.forEach(function (f) {
if (f.kind === 'image') {
const img = document.createElement('img');
img.src = f.url;
img.alt = f.name;
gallery.appendChild(img);
} else {
console.log('received', f.name, f.size + ' bytes');
}
});
}
importShared();Sayfa açıkken gelen yeni dosyalar da appmint:fileopen tetikler, dosya başına bir olay:
window.addEventListener('appmint:fileopen', function (e) { addToGallery(e.detail); });Kullanıcının paylaştığı her şeyi tek bir istekte, gerçek dosyalar olarak yükleme:
async function uploadShared() {
if (!window.AppMint || typeof AppMint.getOpenedFiles !== 'function') return;
const files = await AppMint.getOpenedFiles();
if (!files.length) return;
const form = new FormData();
for (const f of files) {
try {
form.append('files', await f.getFile(), f.name); // url-only media is fetched here
} catch (e) {
console.warn('skipped', f.name, e.message); // released earlier
}
}
await fetch('/api/upload', { method: 'POST', body: form });
}Notlar: Liste bir kopyadır; daha fazla dosya geldikçe büyür. AppMint.releaseOpenedFile(f) ile bıraktığınız dosyalar listede kalır, ancak url artık çalışmaz.
AppMint.releaseOpenedFile yardımcı#
AppMint.releaseOpenedFile(file)
Örnek
Sayfanız işini bitirdikten sonra, uygulamaya paylaşılan veya uygulamayla açılan bir dosyanın uygulama önbelleğindeki kopyasını siler.
Döndürür: hiçbir şey. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın.
async function importAndForget() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return;
const f = await AppMint.getOpenedFile();
if (!f) return;
const file = await f.getFile(); // take your own copy of the bytes first
await saveToMyDatabase(file);
AppMint.releaseOpenedFile(f); // then free the cache on disk
}Paylaşılan bir video f.url üzerinden oynar; bu yüzden onu yalnızca oynatma bittiğinde bırakın:
async function playShared() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return;
const f = await AppMint.getOpenedFile();
if (!f || f.kind !== 'video') return;
const video = document.querySelector('video');
video.src = f.url;
video.play();
video.addEventListener('ended', function () {
video.removeAttribute('src');
video.load();
AppMint.releaseOpenedFile(f); // the url stops working from here
}, { once: true });
}Paylaşılan fotoğraflardan bir grubu içe aktardıktan sonra, önbellekteki her kopyayı tek seferde serbest bırakın:
async function importAllPhotos() {
if (!window.AppMint || typeof AppMint.getOpenedFiles !== 'function') return;
const files = await AppMint.getOpenedFiles();
for (const f of files) {
if (f.kind !== 'image') continue;
const file = await f.getFile(); // fetched from f.url
await savePhoto(file);
AppMint.releaseOpenedFile(f);
}
}Notlar: Aldığınız nesneyi verin (token değeri gerekir). Zaten çektiğiniz bir File geçerli kalır; url çalışmayı bırakır ve getFile(), File zaten alınmadıysa reddedilir. Hâlâ f.url üzerinden oynattığınız bir videoyu bırakmayın. Uygulama ekranı kapandığında bu kopyaları da temizler; bu yüzden erken bırakmak, uzun bir oturumda disk alanıyla ilgilidir.
openedFileChunk köprü#
window.WebToApk.openedFileChunk(token: String, offset: String, len: Int): String
AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile() için dahili. Sayfa, kendisine itilmek yerine çeker: soğuk başlangıçta açılan bir dosya istenene kadar bekletilir, bu yüzden geç bağlanan bir SPA de onu alır. Her dosyanın meta verisi `kind` (image | video | audio | document | data) ve `url` taşır - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, bayt aralıklarıyla önbellek kopyasından sunulur; böylece paylaşılan bir video <video src> içine akar ve ileri sarılabilir. Veri dosyaları ve belgeler de MAX_IO_CHUNK dilimleriyle bir File içine çekilir; medya ve 64 MB'ı aşan her şey yalnızca url olarak kalır (getFile() istendiğinde getirir), böylece 300 MB'lık bir klip hiçbir zaman bir JS dizisinde durmaz.
Kendi başına değil, grubuyla anlatılır: Uygulamaya paylaşılan veya uygulamayla açılan dosyalar.
Örnek
AppMint.getOpenedFile() arkasındaki dahili işleyiş: paylaşılan veya açılan bir dosyanın baytlarından bir dilim döndürür; yardımcı bunları bir File içinde birleştirir. Sayfalar genel API'yi kullanmalıdır - f.file, f.getFile() veya f.url.
Döndürür: (eşzamanlı) offset konumundan başlayan en fazla len baytlık bir base64 dizesi (offset dize olarak geçirilir, bu yüzden 2 GB'ı aşan dosyalar da çalışır); dosyanın sonunda, bilinmeyen veya bırakılmış bir token için ya da okuma hatasında "". Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın.
Genel API (bunu kullanın):
if (window.AppMint && typeof AppMint.getOpenedFile === 'function') {
AppMint.getOpenedFile().then(function (f) {
if (!f) return;
return f.getFile().then(function (file) { console.log('got', file.size, 'bytes'); });
});
}Yardımcının onunla yaptığı, yalnızca argümanları açıklamak için gösterilmiştir:
if (window.WebToApk && typeof WebToApk.openedFileChunk === 'function') {
const meta = JSON.parse(WebToApk.openedFilesPending() || '[]')[0];
if (meta) {
const b64 = WebToApk.openedFileChunk(meta.token, '0', WebToApk.openedFileMaxChunk());
console.log('first slice is', atob(b64).length, 'bytes of', meta.size);
}
}Çok büyük bir paylaşılan dosyayı dilimsiz okuma - f.url akıtın ve ilerlemeyi gösterin (burada CSV satırlarını sayarak):
async function countRows() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return;
const f = await AppMint.getOpenedFile();
if (!f) return;
const res = await fetch(f.url); // served from disk, no base64 round trips
if (!res.ok) throw new Error('shared file unavailable (' + res.status + ')');
const reader = res.body.getReader();
let seen = 0, rows = 0;
for (;;) {
const step = await reader.read();
if (step.done) break;
seen += step.value.length;
for (let i = 0; i < step.value.length; i++) if (step.value[i] === 10) rows++;
showProgress(seen / f.size);
}
console.log(rows + ' rows in ' + f.name);
}Notlar: len, 1 bayt … 4 MB aralığına sıkıştırılır. Medya dosyaları için f.url akıtmak, dilim çekmekten çok daha ucuzdur.
openedFileCollected köprü#
window.WebToApk.openedFileCollected(token: String)
AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile() için dahili. Sayfa, kendisine itilmek yerine çeker: soğuk başlangıçta açılan bir dosya istenene kadar bekletilir, bu yüzden geç bağlanan bir SPA de onu alır. Her dosyanın meta verisi `kind` (image | video | audio | document | data) ve `url` taşır - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, bayt aralıklarıyla önbellek kopyasından sunulur; böylece paylaşılan bir video <video src> içine akar ve ileri sarılabilir. Veri dosyaları ve belgeler de MAX_IO_CHUNK dilimleriyle bir File içine çekilir; medya ve 64 MB'ı aşan her şey yalnızca url olarak kalır (getFile() istendiğinde getirir), böylece 300 MB'lık bir klip hiçbir zaman bir JS dizisinde durmaz.
Kendi başına değil, grubuyla anlatılır: Uygulamaya paylaşılan veya uygulamayla açılan dosyalar.
Örnek
AppMint.getOpenedFile() arkasındaki dahili işleyiş: paylaşılan veya açılan bir dosyayı toplanmış olarak işaretler; böylece artık "yeni" olarak sunulmaz ama önbellek kopyası korunur. Sayfalar genel API'yi kullanmalıdır; bunu doğrudan çağırmanın bir nedeni yoktur.
Döndürür: hiçbir şey. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın.
Genel API (bunu kullanın) - her dosya bir kez toplanır ve sayfanıza verilir:
if (window.AppMint && typeof AppMint.getOpenedFiles === 'function') {
AppMint.getOpenedFiles().then(function (files) {
files.forEach(function (f) { console.log(f.name, f.kind); });
});
}
window.addEventListener('appmint:fileopen', function (e) { console.log('new file', e.detail.name); });Başlangıçta toplanan bir dosya hem listededir hem de olayla duyurulur; bu yüzden her dosyayı bir kez işlemek için kendi işlemenizi token ile anahtarlayın:
const handled = new Set();
function handleOnce(f) {
if (handled.has(f.token)) return;
handled.add(f.token);
addToInbox(f);
}
window.addEventListener('appmint:fileopen', function (e) { handleOnce(e.detail); });
if (window.AppMint && typeof AppMint.getOpenedFiles === 'function') {
AppMint.getOpenedFiles().then(function (files) { files.forEach(handleOnce); });
}Okunamayan bir dosya yine de toplanır; bunun yerine appmint:fileopenerror üzerinden bir kez bildirilir appmint:fileopen:
window.addEventListener('appmint:fileopenerror', function (e) {
const d = e.detail; // {name, error}
showBanner('Could not open "' + d.name + '". Try sharing it again.');
console.warn('opened file failed:', d.error);
});Notlar: Bunu kendiniz çağırmak, bir dosyayı kimseye vermeden AppMint.getOpenedFile() ve appmint:fileopen olayından gizler. Önbellek kopyasını serbest bırakmak için şunu kullanın AppMint.releaseOpenedFile(f).
openedFileMaxChunk köprü#
window.WebToApk.openedFileMaxChunk(): Int
AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile() için dahili. Sayfa, kendisine itilmek yerine çeker: soğuk başlangıçta açılan bir dosya istenene kadar bekletilir, bu yüzden geç bağlanan bir SPA de onu alır. Her dosyanın meta verisi `kind` (image | video | audio | document | data) ve `url` taşır - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, bayt aralıklarıyla önbellek kopyasından sunulur; böylece paylaşılan bir video <video src> içine akar ve ileri sarılabilir. Veri dosyaları ve belgeler de MAX_IO_CHUNK dilimleriyle bir File içine çekilir; medya ve 64 MB'ı aşan her şey yalnızca url olarak kalır (getFile() istendiğinde getirir), böylece 300 MB'lık bir klip hiçbir zaman bir JS dizisinde durmaz.
Kendi başına değil, grubuyla anlatılır: Uygulamaya paylaşılan veya uygulamayla açılan dosyalar.
Örnek
AppMint.getOpenedFile() arkasındaki dahili işleyiş: openedFileChunk işlevinin tek çağrıda döndürdüğü en büyük dilim (4 MB). Sayfalar, zaten bu boyutta dilimlerle okuyan genel API'yi kullanmalıdır.
Döndürür: (eşzamanlı) bayt cinsinden bir sayı (4194304). Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın.
Genel API (bunu kullanın):
if (window.AppMint && typeof AppMint.getOpenedFile === 'function') {
AppMint.getOpenedFile().then(function (f) {
if (f && f.file) console.log('pulled in 4 MB slices:', f.file.size, 'bytes');
});
}Yalnızca sayıyı bilmek istiyorsanız ham çağrı:
if (window.WebToApk && typeof WebToApk.openedFileMaxChunk === 'function') {
console.log('slice size', WebToApk.openedFileMaxChunk());
}Yavaş bir içe aktarmayı profillerken, yardımcının bekleyen her dosya için kaç köprü çağrısı yapacağını tahmin etme:
if (window.WebToApk && typeof WebToApk.openedFileMaxChunk === 'function') {
const slice = WebToApk.openedFileMaxChunk();
JSON.parse(WebToApk.openedFilesPending() || '[]').forEach(function (m) {
console.log(m.name, (m.size / 1048576).toFixed(1) + ' MB =', Math.ceil(m.size / slice), 'slice(s)');
});
}Notlar: Dosya erişimi köprüsündeki getMaxIoChunkSize() ile aynı sınır.
openedFileRelease köprü#
window.WebToApk.openedFileRelease(token: String)
AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile() için dahili. Sayfa, kendisine itilmek yerine çeker: soğuk başlangıçta açılan bir dosya istenene kadar bekletilir, bu yüzden geç bağlanan bir SPA de onu alır. Her dosyanın meta verisi `kind` (image | video | audio | document | data) ve `url` taşır - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, bayt aralıklarıyla önbellek kopyasından sunulur; böylece paylaşılan bir video <video src> içine akar ve ileri sarılabilir. Veri dosyaları ve belgeler de MAX_IO_CHUNK dilimleriyle bir File içine çekilir; medya ve 64 MB'ı aşan her şey yalnızca url olarak kalır (getFile() istendiğinde getirir), böylece 300 MB'lık bir klip hiçbir zaman bir JS dizisinde durmaz.
Kendi başına değil, grubuyla anlatılır: Uygulamaya paylaşılan veya uygulamayla açılan dosyalar.
Örnek
AppMint.releaseOpenedFile(f) arkasındaki dahili işleyiş: paylaşılan veya açılan bir dosyanın önbellek kopyasını token ile siler. Sayfalar genel API'yi kullanmalıdır.
Döndürür: hiçbir şey. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın.
Genel API (bunu kullanın):
async function useAndRelease() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return;
const f = await AppMint.getOpenedFile();
if (!f) return;
const file = await f.getFile(); // keep your own copy first
await store(file);
AppMint.releaseOpenedFile(f); // calls WebToApk.openedFileRelease(f.token)
}Kullanıcı paylaşılan bir dosyayı içe aktarmadan kapatır - önbellekteki kopyayı hemen serbest bırakın:
async function offerImport() {
if (!window.AppMint || typeof AppMint.getOpenedFile !== 'function') return;
const f = await AppMint.getOpenedFile();
if (!f) return;
const box = showImportPrompt(f.name, f.size); // your own "Import / Discard" UI
box.querySelector('.discard').addEventListener('click', function () {
AppMint.releaseOpenedFile(f);
box.remove();
});
box.querySelector('.import').addEventListener('click', async function () {
await store(await f.getFile());
AppMint.releaseOpenedFile(f);
box.remove();
});
}Uygulamanın kullanamadığı bir dosya reddedilir reddedilmez serbest bırakılır:
window.addEventListener('appmint:fileopen', function (e) {
const f = e.detail;
if (!/\.(gpx|tcx)$/i.test(f.name)) {
alert(f.name + ' is not a GPX or TCX activity file.');
AppMint.releaseOpenedFile(f);
return;
}
importActivity(f.text); // gpx/tcx arrive as text
});Notlar: Bıraktıktan sonra f.url bir hata döndürür ve openedFileChunk o token için "" döndürür. Zaten elinizde olan bir File nesnesi etkilenmez.
openedFilesPending köprü#
window.WebToApk.openedFilesPending(): String
Yabancı bir sayfa hiçbir şey alamaz: dosyalar uygulamanın kendi sayfası için bekletilir.
Örnek
AppMint.getOpenedFile() / AppMint.getOpenedFiles() arkasındaki dahili işleyiş: sayfanın henüz toplamadığı paylaşılan veya açılan dosyaları listeler (yalnızca meta veri, bayt yok). Sayfalar genel API'yi kullanmalıdır.
Döndürür: (eşzamanlı) bir JSON dizesi: {token, name, mimeType, size, isText, kind, url} dizisi. Hiçbir şey beklemiyorsa []. Gerekir: derleme yaparken Diğer Uygulamalardan Paylaşım Al seçeneğini açın (açılmazsa liste her zaman boştur ve AppMint yardımcıları yüklenmez).
Genel API (bunu kullanın):
if (window.AppMint && typeof AppMint.getOpenedFile === 'function') {
AppMint.getOpenedFile().then(function (f) {
if (f) console.log('opened with the app:', f.name, f.kind);
});
}
window.addEventListener('appmint:fileopen', function (e) { console.log('arrived:', e.detail.name); });Yalnızca hata ayıklama için - toplamadan neyin beklediğine göz atın:
if (window.WebToApk && typeof WebToApk.openedFilesPending === 'function') {
const waiting = JSON.parse(WebToApk.openedFilesPending() || '[]');
console.log(waiting.length + ' file(s) waiting', waiting.map(function (m) { return m.name; }));
}Sayfaya hiç ulaşmayan bir dosyanın hatasını ayıklama - hâlâ neyin beklediğini ve f.file olarak mı yoksa yalnızca şu şekilde mi geleceğini görün f.url:
if (window.WebToApk && typeof WebToApk.openedFilesPending === 'function') {
const STREAM_LIMIT = 64 * 1024 * 1024; // the helper's url-only threshold
JSON.parse(WebToApk.openedFilesPending() || '[]').forEach(function (m) {
const urlOnly = m.kind === 'image' || m.kind === 'video' || m.kind === 'audio' || m.size > STREAM_LIMIT;
console.log(m.name, m.mimeType, m.size + ' bytes',
urlOnly ? 'will come as url only' : 'will be pulled into f.file',
m.isText ? '(text)' : '');
});
}Notlar: Yardımcı bunları load sonrasında ve yeni bir dosya geldiğinde otomatik olarak toplar; bu yüzden bir sayfa burada nadiren bir şey görür. Toplandıktan sonra dosya bu listeden çıkar ama bırakılana kadar okunabilir kalır.