API پل جاوااسکریپت
فایلها: باز شده با این اپلیکیشن
جمعآوری آنچه اپلیکیشن دیگری از طریق «باز کردن با» تحویل داده، در تکههایی که صفحه میکشد.
AppMint.getOpenedFile کمککننده#
AppMint.getOpenedFile()
نمونه
فایلی را که به اپلیکیشن اشتراکگذاری شده یا با آن («باز کردن با…») باز شده به صفحهٔ شما میدهد، هر قدر هم صفحهٔ شما دیر شروع شود.
مقدار بازگشتی: Promise<object | null> - null وقتی اپلیکیشن عادی باز شده بود. شیء token, name, mimeType, size, kind, url, file, getFile() دارد، بهعلاوهٔ text (فایلهای متنی تا 32 مگابایت) یا base64 (دیگر فایلهای داده تا 8 مگابایت) وقتی ارزان باشد. kind برابر 'image' | 'video' | 'audio' | 'document' | 'data' است. پیشنیاز: هنگام ساخت Receive Shares From Other Apps را روشن کنید و انواع فایلی را که اپلیکیشن شما میپذیرد علامت بزنید.
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();یا گوش بدهید - رویداد (و قلاب اختیاری window.onAppMintFileOpen) برای هر فایل جدید یک بار فعال میشود، با همان شیئی که 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}
});در یک اپلیکیشن React، یک هوک کوچک فایل را هر قدر هم کامپوننت دیر سوار شود میگیرد و فایلهای جدید را دنبال میکند:
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;
}نکتهها: تصاویر، ویدیوها، صداها و هر فایل بالای 64 مگابایت فقط بهصورت url میرسند (file برابر null است)؛ وقتی واقعاً به بایتها نیاز دارید f.getFile() را صدا بزنید. فایلهای داده و اسناد هم بهصورت f.file میرسند. فایل تا وقتی بپرسید برای صفحهٔ شما نگه داشته میشود، پس یک SPA که دیر سوار میشود هم آن را میگیرد؛ هر بار جدیدترین برگردانده میشود. وقتی اپلیکیشن از قبل باز است و فایل دیگری میرسد، رویداد دوباره فعال میشود. وقتی تمام شد AppMint.releaseOpenedFile(f) را صدا بزنید تا نسخهٔ کششده آزاد شود.
AppMint.getOpenedFiles کمککننده#
AppMint.getOpenedFiles()
نمونه
هر فایلی را که در این نشست به اپلیکیشن اشتراکگذاری یا با آن باز شده به صفحهٔ شما میدهد - وقتی کاربر چند عکس را یکجا به اشتراک میگذارد مفید است.
مقدار بازگشتی: Promise<Array> از همان اشیایی که AppMint.getOpenedFile() برمیگرداند (token, name, mimeType, size, kind, url, file, getFile()، و text / base64 وقتی ارزان باشد). وقتی چیزی دریافت نشده آرایهٔ خالی. پیشنیاز: هنگام ساخت Receive Shares From Other Apps را روشن کنید و انواع فایلی را که اپلیکیشن شما میپذیرد علامت بزنید.
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();فایلهای جدیدی که هنگام باز بودن صفحه میرسند هم appmint:fileopen را فعال میکنند، یک رویداد برای هر فایل:
window.addEventListener('appmint:fileopen', function (e) { addToGallery(e.detail); });هر آنچه کاربر به اشتراک گذاشته را در یک درخواست، بهصورت فایلهای واقعی آپلود کنید:
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 });
}نکتهها: فهرست یک کپی است؛ با رسیدن فایلهای بیشتر بزرگ میشود. فایلهایی که با AppMint.releaseOpenedFile(f) آزاد کردهاید در فهرست میمانند، اما url آنها دیگر کار نمیکند.
AppMint.releaseOpenedFile کمککننده#
AppMint.releaseOpenedFile(file)
نمونه
نسخهٔ کششدهٔ اپلیکیشن از فایلی را که به اپلیکیشن اشتراکگذاری یا با آن باز شده حذف میکند، وقتی کار صفحهٔ شما با آن تمام شد.
مقدار بازگشتی: هیچ. پیشنیاز: هنگام ساخت Receive Shares From Other Apps را روشن کنید.
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
}یک ویدیوی اشتراکگذاریشده از f.url پخش میشود، پس فقط وقتی پخش تمام شد آزادش کنید:
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 });
}پس از وارد کردن دستهای از عکسهای اشتراکگذاریشده، همهٔ نسخههای کششده را یکجا آزاد کنید:
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);
}
}نکتهها: شیئی را که گرفتهاید بدهید (به token آن نیاز دارد). یک File که از قبل کشیدهاید معتبر میماند؛ url از کار میافتد و getFile() رد میشود مگر اینکه از قبل File را گرفته باشد. ویدیویی را که هنوز از f.url پخش میکنید آزاد نکنید. اپلیکیشن هنگام بسته شدن صفحهاش هم این نسخهها را پاک میکند، پس آزادسازی زودهنگام برای فضای دیسک در یک نشست طولانی است.
openedFileChunk پل#
window.WebToApk.openedFileChunk(token: String, offset: String, len: Int): String
داخلی برای AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). صفحه میکشد، نه اینکه به سمتش فشار داده شود: فایلی که در راهاندازی سرد باز شده تا وقتی درخواست شود کنار گذاشته میشود، پس یک SPA که دیر سوار میشود هم آن را میگیرد. فرادادههای هر فایل `kind` (image | video | audio | document | data) و `url` را دارد - https://appassets.androidplatform.net/appmint-shared/<token>/<name>، از نسخهٔ کش با محدودههای بایتی ارائه میشود، پس یک ویدیوی اشتراکگذاریشده در <video src> استریم میشود و جستوجو میکند. فایلهای داده و اسناد هم در برشهای MAX_IO_CHUNK به یک File کشیده میشوند؛ رسانه و هر چیز بالای 64 مگابایت فقط url میمانند (getFile() در صورت نیاز میگیرد)، پس یک کلیپ 300 مگابایتی هرگز در یک آرایهٔ JS نمینشیند.
در گروه خودش توصیف شده، فایلهایی که به اپلیکیشن اشتراکگذاری یا با آن باز میشوند، نه بهتنهایی.
نمونه
زیرساخت داخلی پشت AppMint.getOpenedFile(): یک برش از بایتهای یک فایل اشتراکگذاریشده یا بازشده را برمیگرداند که کمکی آنها را به یک File میچسباند. صفحهها باید از API عمومی استفاده کنند - f.file، f.getFile() یا f.url.
مقدار بازگشتی: (همگام) یک رشتهٔ base64 تا len بایت از offset به بعد (آفست بهصورت رشته داده میشود، پس فایلهای بالای 2 گیگابایت هم کار میکنند)؛ "" در انتهای فایل، برای توکن ناشناخته یا آزادشده، یا در خطای خواندن. پیشنیاز: هنگام ساخت، Receive Shares From Other Apps را روشن کنید.
API عمومی (از این استفاده کنید):
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'); });
});
}کاری که کمکی با آن میکند، فقط برای توضیح آرگومانها:
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);
}
}خواندن یک فایل اشتراکگذاریشدهٔ بسیار بزرگ بدون برش - f.url را استریم کنید و پیشرفت را نشان دهید (اینجا شمارش ردیفهای CSV):
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);
}نکتهها: len به محدودهٔ 1 بایت … 4 مگابایت محدود میشود. برای فایلهای رسانهای، استریم f.url بسیار ارزانتر از کشیدن برشهاست.
openedFileCollected پل#
window.WebToApk.openedFileCollected(token: String)
داخلی برای AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). صفحه میکشد، نه اینکه به سمتش فشار داده شود: فایلی که در راهاندازی سرد باز شده تا وقتی درخواست شود کنار گذاشته میشود، پس یک SPA که دیر سوار میشود هم آن را میگیرد. فرادادههای هر فایل `kind` (image | video | audio | document | data) و `url` را دارد - https://appassets.androidplatform.net/appmint-shared/<token>/<name>، از نسخهٔ کش با محدودههای بایتی ارائه میشود، پس یک ویدیوی اشتراکگذاریشده در <video src> استریم میشود و جستوجو میکند. فایلهای داده و اسناد هم در برشهای MAX_IO_CHUNK به یک File کشیده میشوند؛ رسانه و هر چیز بالای 64 مگابایت فقط url میمانند (getFile() در صورت نیاز میگیرد)، پس یک کلیپ 300 مگابایتی هرگز در یک آرایهٔ JS نمینشیند.
در گروه خودش توصیف شده، فایلهایی که به اپلیکیشن اشتراکگذاری یا با آن باز میشوند، نه بهتنهایی.
نمونه
زیرساخت داخلی پشت AppMint.getOpenedFile(): یک فایل اشتراکگذاریشده یا بازشده را جمعآوریشده علامت میزند، پس دیگر «جدید» عرضه نمیشود اما نسخهٔ کششدهاش نگه داشته میشود. صفحهها باید از API عمومی استفاده کنند؛ دلیلی برای صدا زدن مستقیم این نیست.
مقدار بازگشتی: هیچ. پیشنیاز: هنگام ساخت Receive Shares From Other Apps را روشن کنید.
API عمومی (از این استفاده کنید) - هر فایل یک بار جمعآوری و به صفحهٔ شما داده میشود:
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); });فایلی که هنگام راهاندازی جمعآوری شده هم در فهرست است و هم با رویداد اعلام میشود، پس پردازش خودتان را بر اساس token کلید بزنید تا هر فایل یک بار پردازش شود:
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); });
}فایلی که خوانده نشد همچنان جمعآوری میشود؛ یک بار از طریق appmint:fileopenerror گزارش میشود، نه 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);
});نکتهها: خودتان صدا زدنش فایلی را از AppMint.getOpenedFile() و رویداد appmint:fileopen پنهان میکند بدون اینکه به کسی بدهد. برای آزاد کردن نسخهٔ کششده از AppMint.releaseOpenedFile(f).
openedFileMaxChunk پل#
window.WebToApk.openedFileMaxChunk(): Int
داخلی برای AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). صفحه میکشد، نه اینکه به سمتش فشار داده شود: فایلی که در راهاندازی سرد باز شده تا وقتی درخواست شود کنار گذاشته میشود، پس یک SPA که دیر سوار میشود هم آن را میگیرد. فرادادههای هر فایل `kind` (image | video | audio | document | data) و `url` را دارد - https://appassets.androidplatform.net/appmint-shared/<token>/<name>، از نسخهٔ کش با محدودههای بایتی ارائه میشود، پس یک ویدیوی اشتراکگذاریشده در <video src> استریم میشود و جستوجو میکند. فایلهای داده و اسناد هم در برشهای MAX_IO_CHUNK به یک File کشیده میشوند؛ رسانه و هر چیز بالای 64 مگابایت فقط url میمانند (getFile() در صورت نیاز میگیرد)، پس یک کلیپ 300 مگابایتی هرگز در یک آرایهٔ JS نمینشیند.
در گروه خودش توصیف شده، فایلهایی که به اپلیکیشن اشتراکگذاری یا با آن باز میشوند، نه بهتنهایی.
نمونه
زیرساخت داخلی پشت AppMint.getOpenedFile(): بزرگترین برشی که openedFileChunk در یک فراخوانی برمیگرداند (4 مگابایت). صفحهها باید از API عمومی استفاده کنند که از قبل با برشهایی به این اندازه میخواند.
مقدار بازگشتی: (همگام) تعداد بایتها (4194304). پیشنیاز: هنگام ساخت، Receive Shares From Other Apps را روشن کنید.
API عمومی (از این استفاده کنید):
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');
});
}فراخوانی خام، اگر فقط میخواهید عدد را بدانید:
if (window.WebToApk && typeof WebToApk.openedFileMaxChunk === 'function') {
console.log('slice size', WebToApk.openedFileMaxChunk());
}برآورد اینکه کمکی برای هر فایل منتظر چند فراخوانی پل انجام میدهد، هنگام پروفایلگیری از یک واردسازی کند:
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)');
});
}نکتهها: همان سقف getMaxIoChunkSize() برای پل دسترسی به فایل.
openedFileRelease پل#
window.WebToApk.openedFileRelease(token: String)
داخلی برای AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). صفحه میکشد، نه اینکه به سمتش فشار داده شود: فایلی که در راهاندازی سرد باز شده تا وقتی درخواست شود کنار گذاشته میشود، پس یک SPA که دیر سوار میشود هم آن را میگیرد. فرادادههای هر فایل `kind` (image | video | audio | document | data) و `url` را دارد - https://appassets.androidplatform.net/appmint-shared/<token>/<name>، از نسخهٔ کش با محدودههای بایتی ارائه میشود، پس یک ویدیوی اشتراکگذاریشده در <video src> استریم میشود و جستوجو میکند. فایلهای داده و اسناد هم در برشهای MAX_IO_CHUNK به یک File کشیده میشوند؛ رسانه و هر چیز بالای 64 مگابایت فقط url میمانند (getFile() در صورت نیاز میگیرد)، پس یک کلیپ 300 مگابایتی هرگز در یک آرایهٔ JS نمینشیند.
در گروه خودش توصیف شده، فایلهایی که به اپلیکیشن اشتراکگذاری یا با آن باز میشوند، نه بهتنهایی.
نمونه
زیرساخت داخلی پشت AppMint.releaseOpenedFile(f): نسخهٔ کششدهٔ یک فایل اشتراکگذاریشده یا بازشده را بر اساس توکن حذف میکند. صفحهها باید از API عمومی استفاده کنند.
مقدار بازگشتی: هیچ. پیشنیاز: هنگام ساخت Receive Shares From Other Apps را روشن کنید.
API عمومی (از این استفاده کنید):
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)
}کاربر یک فایل اشتراکگذاریشده را بدون وارد کردن رد میکند - نسخهٔ کششده را فوراً آزاد کنید:
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();
});
}فایلی که اپلیکیشن نمیتواند از آن استفاده کند همینکه رد شد آزاد میشود:
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
});نکتهها: پس از آزادسازی، f.url خطا برمیگرداند و openedFileChunk برای آن توکن "" برمیگرداند. یک شیء File که از قبل دارید تأثیری نمیپذیرد.
openedFilesPending پل#
window.WebToApk.openedFilesPending(): String
یک صفحهٔ خارجی چیزی نمیگیرد: فایلها برای صفحهٔ خودِ اپلیکیشن کنار گذاشته میمانند.
نمونه
زیرساخت داخلی پشت AppMint.getOpenedFile() / AppMint.getOpenedFiles(): فایلهای اشتراکگذاریشده یا بازشدهای را که صفحه هنوز جمع نکرده فهرست میکند (فقط فراداده، بدون بایت). صفحهها باید از API عمومی استفاده کنند.
مقدار بازگشتی: (همگام) یک رشتهٔ JSON: آرایهای از {token, name, mimeType, size, isText, kind, url}. [] وقتی چیزی منتظر نیست. پیشنیاز: هنگام ساخت، Receive Shares From Other Apps را روشن کنید (بدون آن فهرست همیشه خالی است و کمکیهای AppMint نصب نمیشوند).
API عمومی (از این استفاده کنید):
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); });فقط برای اشکالزدایی - نگاهی به آنچه منتظر است بیندازید بدون جمعآوری آن:
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; }));
}اشکالزدایی فایلی که هرگز به صفحه نرسید - ببینید چه چیزی هنوز منتظر است و آیا بهصورت f.file میرسد یا فقط بهصورت 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)' : '');
});
}نکتهها: کمکی اینها را پس از load و هر بار که فایل جدیدی میرسد بهصورت خودکار جمع میکند، پس صفحه بهندرت اینجا چیزی میبیند. پس از جمعآوری، فایل از این فهرست خارج میشود اما تا آزادسازی قابل خواندن میماند.