Créer un APK gratuit

API du pont JavaScript

Fichiers : ouverts avec cette application

Collecter ce qu'une autre application a transmis via « Ouvrir avec », en blocs que la page récupère.

AppMint.getOpenedFile assistant#

AppMint.getOpenedFile()

Exemple

Donne à votre page le fichier qui a été partagé avec l'application, ou ouvert avec elle (« Ouvrir avec… »), quel que soit le moment tardif où votre page démarre.

Renvoie : Promise<object | null> - null quand l'application a été ouverte normalement. L'objet contient token, name, mimeType, size, kind, url, file, getFile(), plus text (fichiers texte jusqu'à 32 Mo) ou base64 (autres fichiers de données jusqu'à 8 Mo) quand c'est peu coûteux. kind vaut 'image' | 'video' | 'audio' | 'document' | 'data'. Nécessite : activez Receive Shares From Other Apps lors de la compilation et cochez les types de fichiers que votre application accepte.

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();

Ou écoutez - l'événement (et le hook facultatif window.onAppMintFileOpen) se déclenche une fois par nouveau fichier, avec le même objet que 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}
});

Dans une application React, un petit hook récupère le fichier quel que soit le moment tardif où le composant se monte, et suit les nouveaux :

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;
}

Remarques : Les images, vidéos, fichiers audio et tout fichier de plus de 64 Mo arrivent uniquement sous forme de url (file vaut null) ; appelez f.getFile() quand vous avez vraiment besoin des octets. Les fichiers de données et les documents arrivent aussi sous forme de f.file. Le fichier est conservé pour votre page jusqu'à ce que vous le demandiez, donc une SPA qui se monte tard le reçoit quand même ; le plus récent est renvoyé à chaque fois. Quand l'application est déjà ouverte et qu'un autre fichier arrive, l'événement se déclenche à nouveau. Appelez AppMint.releaseOpenedFile(f) une fois terminé pour libérer la copie en cache.

AppMint.getOpenedFiles assistant#

AppMint.getOpenedFiles()

Exemple

Donne à votre page tous les fichiers partagés avec l'application, ou ouverts avec elle, pendant cette session - utile quand l'utilisateur partage plusieurs photos à la fois.

Renvoie : Promise<Array> des mêmes objets que AppMint.getOpenedFile() renvoie (token, name, mimeType, size, kind, url, file, getFile(), et text / base64 quand c'est peu coûteux). Un tableau vide quand rien n'a été reçu. Nécessite : activez Receive Shares From Other Apps lors de la compilation et cochez les types de fichiers que votre application accepte.

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();

Les nouveaux fichiers qui arrivent pendant que la page est ouverte déclenchent aussi appmint:fileopen, un événement par fichier :

window.addEventListener('appmint:fileopen', function (e) { addToGallery(e.detail); });

Envoyer en une seule requête tout ce que l'utilisateur a partagé, sous forme de vrais fichiers :

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 });
}

Remarques : La liste est une copie ; elle s'allonge à mesure que d'autres fichiers arrivent. Les fichiers que vous avez libérés avec AppMint.releaseOpenedFile(f) restent dans la liste, mais leur url ne fonctionne plus.

AppMint.releaseOpenedFile assistant#

AppMint.releaseOpenedFile(file)

Exemple

Supprime la copie en cache faite par l'application d'un fichier partagé avec l'application ou ouvert avec elle, une fois que votre page n'en a plus besoin.

Renvoie : rien. Nécessite : activez Receive Shares From Other Apps lors de la compilation.

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
}

Une vidéo partagée se lit depuis f.url, ne la libérez donc qu'une fois la lecture terminée :

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 });
}

Après avoir importé un lot de photos partagées, libérer d'un coup toutes les copies en cache :

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);
  }
}

Remarques : Passez l'objet que vous avez reçu (il a besoin de son token). Un File déjà récupéré reste valide ; l'url cesse de fonctionner, et getFile() rejette sauf s'il avait déjà récupéré le File. Ne libérez pas une vidéo que vous êtes encore en train de lire depuis f.url. L'application efface aussi ces copies quand son écran est fermé, donc libérer tôt sert à ménager l'espace disque pendant une longue session.

openedFileChunk pont#

window.WebToApk.openedFileChunk(token: String, offset: String, len: Int): String

Interne à AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). La page tire plutôt qu'on ne lui pousse : un fichier ouvert au démarrage à froid est mis en attente jusqu'à ce qu'on le demande, donc une SPA qui se monte tard le reçoit quand même. Les métadonnées de chaque fichier contiennent `kind` (image | video | audio | document | data) et `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, servi depuis la copie en cache avec plages d'octets, de sorte qu'une vidéo partagée est diffusée dans <video src> et permet la recherche. Les fichiers de données et les documents sont aussi récupérés par tranches MAX_IO_CHUNK dans un File ; les médias et tout ce qui dépasse 64 Mo restent en url seule (getFile() récupère à la demande), donc un clip de 300 Mo ne se retrouve jamais dans un tableau JS.

Décrit par son groupe, Fichiers partagés avec l'application, ou ouverts avec elle, plutôt qu'à part.

Exemple

Mécanisme interne derrière AppMint.getOpenedFile() : renvoie une tranche des octets d'un fichier partagé ou ouvert, que le helper assemble en un File. Les pages doivent utiliser l'API publique - f.file, f.getFile() ou f.url.

Renvoie : (sync) une chaîne base64 d'au plus len octets à partir de offset (le décalage est passé sous forme de chaîne, donc les fichiers de plus de 2 Go fonctionnent) ; "" à la fin du fichier, pour un jeton inconnu ou libéré, ou en cas d'erreur de lecture. Nécessite : activez Receive Shares From Other Apps lors de la compilation.

L'API publique (à utiliser) :

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'); });
  });
}

Ce que le helper en fait, montré uniquement pour expliquer les 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);
  }
}

Lire un très gros fichier partagé sans tranches - diffuser f.url en flux et afficher la progression (ici en comptant les lignes d'un 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);
}

Remarques : len est limité à 1 octet … 4 Mo. Pour les fichiers médias, diffuser f.url en flux coûte bien moins cher que récupérer des tranches.

openedFileCollected pont#

window.WebToApk.openedFileCollected(token: String)

Interne à AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). La page tire plutôt qu'on ne lui pousse : un fichier ouvert au démarrage à froid est mis en attente jusqu'à ce qu'on le demande, donc une SPA qui se monte tard le reçoit quand même. Les métadonnées de chaque fichier contiennent `kind` (image | video | audio | document | data) et `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, servi depuis la copie en cache avec plages d'octets, de sorte qu'une vidéo partagée est diffusée dans <video src> et permet la recherche. Les fichiers de données et les documents sont aussi récupérés par tranches MAX_IO_CHUNK dans un File ; les médias et tout ce qui dépasse 64 Mo restent en url seule (getFile() récupère à la demande), donc un clip de 300 Mo ne se retrouve jamais dans un tableau JS.

Décrit par son groupe, Fichiers partagés avec l'application, ou ouverts avec elle, plutôt qu'à part.

Exemple

Mécanisme interne derrière AppMint.getOpenedFile() : marque un fichier partagé ou ouvert comme collecté, de sorte qu'il n'est plus proposé comme « nouveau » mais que sa copie en cache est conservée. Les pages doivent utiliser l'API publique ; il n'y a aucune raison de l'appeler directement.

Renvoie : rien. Nécessite : activez Receive Shares From Other Apps lors de la compilation.

L'API publique (à utiliser) - chaque fichier est collecté une fois et remis à votre 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); });

Un fichier collecté au démarrage est à la fois dans la liste et annoncé par l'événement ; identifiez donc votre traitement par token pour traiter chaque fichier une seule fois :

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); });
}

Un fichier qui n'a pas pu être lu est tout de même collecté ; il est signalé une fois via appmint:fileopenerror au lieu de 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);
});

Remarques : L'appeler vous-même cacherait un fichier à AppMint.getOpenedFile() et à l'événement appmint:fileopen sans le donner à personne. Pour libérer la copie en cache, utilisez AppMint.releaseOpenedFile(f).

openedFileMaxChunk pont#

window.WebToApk.openedFileMaxChunk(): Int

Interne à AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). La page tire plutôt qu'on ne lui pousse : un fichier ouvert au démarrage à froid est mis en attente jusqu'à ce qu'on le demande, donc une SPA qui se monte tard le reçoit quand même. Les métadonnées de chaque fichier contiennent `kind` (image | video | audio | document | data) et `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, servi depuis la copie en cache avec plages d'octets, de sorte qu'une vidéo partagée est diffusée dans <video src> et permet la recherche. Les fichiers de données et les documents sont aussi récupérés par tranches MAX_IO_CHUNK dans un File ; les médias et tout ce qui dépasse 64 Mo restent en url seule (getFile() récupère à la demande), donc un clip de 300 Mo ne se retrouve jamais dans un tableau JS.

Décrit par son groupe, Fichiers partagés avec l'application, ou ouverts avec elle, plutôt qu'à part.

Exemple

Mécanisme interne derrière AppMint.getOpenedFile() : la plus grande tranche que openedFileChunk renvoie en un appel (4 Mo). Les pages doivent utiliser l'API publique, qui lit déjà par tranches de cette taille.

Renvoie : (sync) un nombre d'octets (4194304). Nécessite : activez Receive Shares From Other Apps lors de la compilation.

L'API publique (à utiliser) :

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');
  });
}

L'appel brut, si vous voulez seulement connaître le nombre :

if (window.WebToApk && typeof WebToApk.openedFileMaxChunk === 'function') {
  console.log('slice size', WebToApk.openedFileMaxChunk());
}

Estimer combien d'appels au pont le helper fera pour chaque fichier en attente, lors du profilage d'une importation lente :

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)');
  });
}

Remarques : Même limite que getMaxIoChunkSize() pour le pont d'accès aux fichiers.

openedFileRelease pont#

window.WebToApk.openedFileRelease(token: String)

Interne à AppMint.getOpenedFile() / getOpenedFiles() / releaseOpenedFile(). La page tire plutôt qu'on ne lui pousse : un fichier ouvert au démarrage à froid est mis en attente jusqu'à ce qu'on le demande, donc une SPA qui se monte tard le reçoit quand même. Les métadonnées de chaque fichier contiennent `kind` (image | video | audio | document | data) et `url` - https://appassets.androidplatform.net/appmint-shared/<token>/<name>, servi depuis la copie en cache avec plages d'octets, de sorte qu'une vidéo partagée est diffusée dans <video src> et permet la recherche. Les fichiers de données et les documents sont aussi récupérés par tranches MAX_IO_CHUNK dans un File ; les médias et tout ce qui dépasse 64 Mo restent en url seule (getFile() récupère à la demande), donc un clip de 300 Mo ne se retrouve jamais dans un tableau JS.

Décrit par son groupe, Fichiers partagés avec l'application, ou ouverts avec elle, plutôt qu'à part.

Exemple

Mécanisme interne derrière AppMint.releaseOpenedFile(f) : supprime la copie en cache d'un fichier partagé ou ouvert, d'après son jeton. Les pages doivent utiliser l'API publique.

Renvoie : rien. Nécessite : activez Receive Shares From Other Apps lors de la compilation.

L'API publique (à utiliser) :

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)
}

L'utilisateur écarte un fichier partagé sans l'importer - libérer immédiatement la copie en cache :

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();
  });
}

Un fichier que l'application ne peut pas utiliser est libéré dès qu'il est refusé :

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
});

Remarques : Après la libération, f.url renvoie une erreur et openedFileChunk renvoie "" pour ce jeton. Un objet File que vous avez déjà n'est pas affecté.

openedFilesPending pont#

window.WebToApk.openedFilesPending(): String

Une page étrangère ne reçoit rien : les fichiers restent en attente pour la page de l'application elle-même.

Exemple

Mécanisme interne derrière AppMint.getOpenedFile() / AppMint.getOpenedFiles() : liste les fichiers partagés ou ouverts que la page n'a pas encore collectés (métadonnées uniquement, sans octets). Les pages doivent utiliser l'API publique.

Renvoie : (sync) une chaîne JSON : un tableau de {token, name, mimeType, size, isText, kind, url}. [] quand rien n'attend. Nécessite : activez Receive Shares From Other Apps lors de la compilation (sans cela la liste est toujours vide et les helpers AppMint ne sont pas installés).

L'API publique (à utiliser) :

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); });

Uniquement pour le débogage - jeter un œil à ce qui attend sans le collecter :

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; }));
}

Déboguer un fichier qui n'est jamais arrivé à la page - voir ce qui attend encore et s'il arrivera sous forme de f.file ou seulement comme 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)' : '');
  });
}

Remarques : Le helper les collecte automatiquement après load et chaque fois qu'un nouveau fichier arrive, donc une page voit rarement quoi que ce soit ici. Une fois collecté, un fichier quitte cette liste mais reste lisible jusqu'à sa libération.

Généré à partir de l'environnement d'exécution de l'application et de ses fichiers d'exemple à chaque compilation de la documentation. Lire en Markdown · Toutes les familles.

Vérifié par rapport au pont publié le 22/10/2026.