JavaScript bridge API
Files: opened with this app
Collecting what another app handed over through "Open with", in chunks the page pulls.
AppMint.getOpenedFile helper#
AppMint.getOpenedFile()
Example
Gives your page the file that was shared to the app, or opened with it ("Open with…"), however late your page starts.
Returns: Promise<object | null> - null when the app was opened normally. The object has token, name, mimeType, size, kind, url, file, getFile(), plus text (text files up to 32 MB) or base64 (other data files up to 8 MB) when cheap. kind is 'image' | 'video' | 'audio' | 'document' | 'data'. Needs: turn on Receive Shares From Other Apps when you build and tick the kinds of files your app accepts.
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();Or listen - the event (and the optional window.onAppMintFileOpen hook) fires once per new file, with the same object as 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}
});Notes: Images, videos, audio and any file over 64 MB come only as url (file is null); call f.getFile() when you really need the bytes. Data files and documents also come as f.file. The file is kept for your page until you ask, so an SPA that mounts late still gets it; the latest one is returned each time. When the app is already open and another file arrives, the event fires again. Call AppMint.releaseOpenedFile(f) when done to free the cached copy.
AppMint.getOpenedFiles helper#
AppMint.getOpenedFiles()
Example
Gives your page every file shared to, or opened with, the app during this session - useful when the user shares several photos at once.
Returns: Promise<Array> of the same objects AppMint.getOpenedFile() returns (token, name, mimeType, size, kind, url, file, getFile(), and text / base64 when cheap). An empty array when nothing was received. Needs: turn on Receive Shares From Other Apps when you build and tick the kinds of files your app accepts.
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();New files that arrive while the page is open also fire appmint:fileopen, one event per file:
window.addEventListener('appmint:fileopen', function (e) { addToGallery(e.detail); });Notes: The list is a copy; it grows as more files arrive. Files you have released with AppMint.releaseOpenedFile(f) stay in the list, but their url no longer works.
AppMint.releaseOpenedFile helper#
AppMint.releaseOpenedFile(file)
Example
Deletes the app's cached copy of a file that was shared to or opened with the app, once your page is done with it.
Returns: nothing. Needs: turn on Receive Shares From Other Apps when you build.
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
}Notes: Pass the object you got (it needs its token). A File you already pulled stays valid; the url stops working, and getFile() rejects unless it had already fetched the File. Do not release a video you are still playing from f.url. The app also clears these copies when its screen is closed, so releasing early is about disk space during a long session.
openedFileChunk bridge#
window.WebToApk.openedFileChunk(token: String, offset: String, len: Int): String
Internal to AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). The page pulls, rather than being pushed at: a file opened on cold start is parked until it is asked for, so an SPA that mounts late still gets it. Each file's metadata carries `kind` (image | video | audio | document | data) and `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, served from the cache copy with byte ranges, so a shared video streams into <video src> and seeks. Data files and documents are also pulled in MAX_IO_CHUNK slices into a File; media and anything over 64 MB stay url-only (getFile() fetches on demand), so a 300 MB clip never sits in a JS array.
Described by its group, Files shared to, or opened with, the app, rather than on its own.
Example
Internal plumbing behind AppMint.getOpenedFile(): returns one slice of a shared or opened file's bytes, which the helper joins into a File. Pages should use the public API - f.file, f.getFile() or f.url.
Returns: (sync) a base64 string of up to len bytes starting at offset (the offset is passed as a string, so files over 2 GB still work); "" at the end of the file, for an unknown or released token, or on a read error. Needs: turn on Receive Shares From Other Apps when you build.
The public API (use this):
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'); });
});
}What the helper does with it, shown only to explain the arguments:
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);
}
}Notes: len is clamped to 1 byte … 4 MB. For media files, streaming f.url is far cheaper than pulling slices.
openedFileCollected bridge#
window.WebToApk.openedFileCollected(token: String)
Internal to AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). The page pulls, rather than being pushed at: a file opened on cold start is parked until it is asked for, so an SPA that mounts late still gets it. Each file's metadata carries `kind` (image | video | audio | document | data) and `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, served from the cache copy with byte ranges, so a shared video streams into <video src> and seeks. Data files and documents are also pulled in MAX_IO_CHUNK slices into a File; media and anything over 64 MB stay url-only (getFile() fetches on demand), so a 300 MB clip never sits in a JS array.
Described by its group, Files shared to, or opened with, the app, rather than on its own.
Example
Internal plumbing behind AppMint.getOpenedFile(): marks a shared or opened file as collected, so it is no longer offered as "new" but its cached copy is kept. Pages should use the public API; there is no reason to call this directly.
Returns: nothing. Needs: turn on Receive Shares From Other Apps when you build.
The public API (use this) - each file is collected once and handed to your page:
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); });Notes: Calling it yourself would hide a file from AppMint.getOpenedFile() and the appmint:fileopen event without giving it to anyone. To free the cached copy, use AppMint.releaseOpenedFile(f).
openedFileMaxChunk bridge#
window.WebToApk.openedFileMaxChunk(): Int
Internal to AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). The page pulls, rather than being pushed at: a file opened on cold start is parked until it is asked for, so an SPA that mounts late still gets it. Each file's metadata carries `kind` (image | video | audio | document | data) and `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, served from the cache copy with byte ranges, so a shared video streams into <video src> and seeks. Data files and documents are also pulled in MAX_IO_CHUNK slices into a File; media and anything over 64 MB stay url-only (getFile() fetches on demand), so a 300 MB clip never sits in a JS array.
Described by its group, Files shared to, or opened with, the app, rather than on its own.
Example
Internal plumbing behind AppMint.getOpenedFile(): the largest slice openedFileChunk returns in one call (4 MB). Pages should use the public API, which already reads in slices of this size.
Returns: (sync) a number of bytes (4194304). Needs: turn on Receive Shares From Other Apps when you build.
The public API (use this):
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');
});
}The raw call, if you only want to know the number:
if (window.WebToApk && typeof WebToApk.openedFileMaxChunk === 'function') {
console.log('slice size', WebToApk.openedFileMaxChunk());
}Notes: Same cap as getMaxIoChunkSize() for the file-access bridge.
openedFileRelease bridge#
window.WebToApk.openedFileRelease(token: String)
Internal to AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). The page pulls, rather than being pushed at: a file opened on cold start is parked until it is asked for, so an SPA that mounts late still gets it. Each file's metadata carries `kind` (image | video | audio | document | data) and `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, served from the cache copy with byte ranges, so a shared video streams into <video src> and seeks. Data files and documents are also pulled in MAX_IO_CHUNK slices into a File; media and anything over 64 MB stay url-only (getFile() fetches on demand), so a 300 MB clip never sits in a JS array.
Described by its group, Files shared to, or opened with, the app, rather than on its own.
Example
Internal plumbing behind AppMint.releaseOpenedFile(f): deletes the cached copy of a shared or opened file, by token. Pages should use the public API.
Returns: nothing. Needs: turn on Receive Shares From Other Apps when you build.
The public API (use this):
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)
}Notes: After release, f.url returns an error and openedFileChunk returns "" for that token. A File object you already have is not affected.
openedFilesPending bridge#
window.WebToApk.openedFilesPending(): String
A foreign page gets nothing: the files stay parked for the app's own page.
Example
Internal plumbing behind AppMint.getOpenedFile() / AppMint.getOpenedFiles(): lists the shared or opened files the page has not collected yet (metadata only, no bytes). Pages should use the public API.
Returns: (sync) a JSON string: an array of {token, name, mimeType, size, isText, kind, url}. [] when nothing is waiting. Needs: turn on Receive Shares From Other Apps when you build (without it the list is always empty and the AppMint helpers are not installed).
The public API (use this):
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); });Only for debugging - peek at what is waiting without collecting it:
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; }));
}Notes: The helper collects these automatically after load and whenever a new file arrives, so a page rarely sees anything here. Once collected, a file leaves this list but stays readable until released.