Aller au contenu principal

Alternative à cordova-plugin-file-transfer pour Capacitor

Remplacez cordova-plugin-file-transfer dans les apps Capacitor : @capacitor/file-transfer pour les transferts simples, Capgo pour l'upload et le téléchargement en arrière-plan.

Illustration de la migration d'une application Cordova vers Capacitor, utilisée pour un guide sur le plugin de transfert de fichiers

La meilleure alternative à cordova-plugin-file-transfer pour une application Capacitor dépend d'une question : le transfert doit-il continuer quand l'application passe en arrière-plan ? Pour les uploads et téléchargements classiques avec suivi de progression, utilisez le plugin @capacitor/file-transfer officiel. Pour les fichiers volumineux, les réseaux instables ou les transferts qui doivent se poursuivre quand l'utilisateur change d'application, utilisez @capgo/capacitor-uploader et @capgo/capacitor-downloader, qui s'appuient sur les API natives de transfert en arrière-plan. Ce guide les compare et répertorie chaque FileTransfer appel.

Le plugin cordova-plugin-file-transfer est-il toujours déprécié ?

L'historique prête à confusion, voici donc les faits :

  • En 2017, l'équipe Apache Cordova a annoncé son intention de déprécier le plugin et a orienté les développeurs vers XMLHttpRequest le niveau 2.
  • Le plugin n'a jamais été marqué comme déprécié sur npm. La version 2.0.0 est sortie en septembre 2023, et la 2.0.1 en août 2026. Le dépôt GitHub est actif.

Il n'est donc pas mort. Mais dans une application Capacitor, il reste un plugin Cordova qui :

  • dépend de cordova-plugin-file et son cdvfile:// et file:// modèle de chemin,
  • ne convient pas à Capacitor Filesystem conversions de répertoires et d’URI,
  • aucun support des transferts en arrière-plan,
  • API au style callback.

Si vous migrez depuis Cordova, le remplacer par des plugins natifs Capacitor élimine l’une des dernières raisons de conserver cordova-plugin-file.

Pourquoi « utiliser juste fetch » échoue sur les gros fichiers

La solution de remplacement suggérée par Apache, XHR, fonctionne pour de petits JSON et des images. Elle échoue pour un vrai transfert de fichiers dans une app hybride :

  • Mémoire. fetch et XHR vous donnent un Blob ou ArrayBuffer dans le WebView. Une vidéo de 500 Mo signifie 500 Mo en mémoire WebView, puis une copie pour l’écrire via le bridge. Sur des appareils Android milieu de gamme, cela fait planter le renderer.
  • Suspension. Quand l’utilisateur change d’app, iOS suspend le WebView. Les requêtes en cours stagnent ou échouent.
  • Pas d’intégration OS. Aucune notification de téléchargement système, aucune option Wi-Fi uniquement, aucune reprise après une coupure de connexion.

Les plugins natifs streament directement entre le disque et le réseau et gardent JavaScript hors du chemin de données.

Les options comparées

Besoin cordova-plugin-file-transfer @capacitor/file-transfer @capgo/capacitor-uploader @capgo/capacitor-downloader
Télécharger sur le disque Oui Oui Non Oui
Envoyer depuis le disque Oui Oui Oui Non
Événements de progression Oui Oui (progress listener) Oui (events) Oui (downloadProgress)
Données de formulaire multipart Oui Oui (par défaut) Oui n/a
PUT binaire brut (URL présignées) Oui Oui (défini Content-Type) Oui (uploadType: 'binary') n/a
Plusieurs fichiers en une seule requête Non Non Oui (files) n/a
Annuler abort() Non removeUpload stop
Pause / reprendre Non Non Non pause, resume
Tentatives Non Non maxRetries Non
Continue en arrière-plan Non Quand l'app est active Oui Oui
Wi-Fi uniquement Non Non Non network: 'wifi-only'
Détails de l'erreur HTTP http_status, body httpStatus, body Statut code dans les événements Chaîne d'erreur dans les événements
Implémentation Web Non Oui Oui (basé sur fetch) Non

La plupart des apps finissent par utiliser @capacitor/file-transfer pour les petits transferts visibles par l'utilisateur et les plugins Capgo pour les files d'attente d'upload média et les téléchargements de contenu hors ligne.

Option 1 : @capacitor/file-transfer

bun add @capacitor/file-transfer @capacitor/filesystem
bunx cap sync

Le plugin nécessite un chemin natif complet. Récupérez-le via @capacitor/filesystem.

Télécharger

import { FileTransfer } from '@capacitor/file-transfer';
import { Filesystem, Directory } from '@capacitor/filesystem';

export async function downloadReport(url: string) {
  const { uri } = await Filesystem.getUri({
    directory: Directory.Data,
    path: 'reports/latest.pdf',
  });

  const progress = await FileTransfer.addListener('progress', (p) => {
    if (p.type === 'download' && p.lengthComputable) {
      console.log(`Downloaded ${Math.round((p.bytes / p.contentLength) * 100)}%`);
    }
  });

  try {
    const result = await FileTransfer.downloadFile({
      url,
      path: uri,
      progress: true,
      headers: { Authorization: 'Bearer <token>' },
    });
    return result.path;
  } catch (error: any) {
    if (error.code === 'OS-PLUG-FLTR-0010') {
      console.error('HTTP error', error.data?.httpStatus, error.data?.body);
    }
    throw error;
  } finally {
    await progress.remove();
  }
}

Envoyer

export async function uploadAvatar(path: string) {
  const result = await FileTransfer.uploadFile({
    url: 'https://api.example.com/v1/avatar',
    path,
    fileKey: 'avatar',
    mimeType: 'image/jpeg',
    headers: { Authorization: 'Bearer <token>' },
    progress: true,
  });
  console.log(result.responseCode, result.response);
}

Les uploads sont en multipart par défaut. Pour un flux brut, par exemple vers une URL S3 présignée, définissez method: 'PUT' et un explicite Content-Type header explicite tel que application/octet-stream.

Les codes d'erreur suivent le OS-PLUG-FLTR-XXXX format. Voici les plus utiles : 0007 fichier introuvable, 0008 échec de la connexion, 0010 statut d'erreur HTTP avec httpStatus et body dans error.data.

Option 2 : uploads en arrière-plan avec @capgo/capacitor-uploader

bun add @capgo/capacitor-uploader
bunx cap sync
import { Uploader } from '@capgo/capacitor-uploader';

await Uploader.addListener('events', async (event) => {
  switch (event.name) {
    case 'uploading':
      console.log(event.id, `${event.payload.percent}%`);
      break;
    case 'completed':
      console.log(event.id, 'done', event.payload.statusCode);
      break;
    case 'failed':
      console.error(event.id, event.payload.error);
      break;
  }
  // Completed and failed events are cached natively until acknowledged
  if (event.eventId) {
    await Uploader.acknowledgeEvent({ eventId: event.eventId });
  }
});

const { id } = await Uploader.startUpload({
  filePath: 'file:///path/to/video.mp4',
  serverUrl: 'https://api.example.com/v1/videos',
  method: 'POST',
  uploadType: 'multipart',
  fileField: 'video',
  parameters: { albumId: '7' },
  headers: { Authorization: 'Bearer <token>' },
  maxRetries: 3,
  notificationTitle: 'Uploading video', // Android only
});

Pour les URLs presigned, utilisez method: 'PUT', qui utilise un corps binaire par défaut :

await Uploader.startUpload({
  filePath,
  serverUrl: presignedUrl,
  method: 'PUT',
  headers: { 'Content-Type': 'video/mp4' },
  mimeType: 'video/mp4',
});

Plusieurs fichiers dans une seule requête multipart :

await Uploader.startUpload({
  serverUrl: 'https://api.example.com/v1/photos',
  method: 'POST',
  uploadType: 'multipart',
  files: [
    { filePath: photo1, fieldName: 'images[]', mimeType: 'image/jpeg' },
    { filePath: photo2, fieldName: 'images[]', mimeType: 'image/jpeg' },
  ],
  headers: { Authorization: 'Bearer <token>' },
});

Annuler avec Uploader.removeUpload({ id }).

Pourquoi accuser réception des événements ? Les événements terminés et échoués sont stockés dans un cache natif persistant, afin qu’ils puissent être rediffusés si l’app était fermée ou en arrière-plan avant d’avoir été traités. L’acquittement supprime l’événement pour éviter qu’il ne soit rediffusé à l’initialisation suivante du plugin.

Configuration iOS. L’uploader utilise un background URLSession. Many apps need no extra setup. If uploads must continue after the app is suspended, add fetch vers UIBackgroundModes. N’ajoutez pas processing sauf si une autre fonctionnalité l’utilise BGTaskScheduler, car App Store Connect rejette les builds qui le déclarent sans BGTaskSchedulerPermittedIdentifiers.

Option 3 : téléchargements en arrière-plan avec @capgo/capacitor-downloader

bun add @capgo/capacitor-downloader
bunx cap sync
import { CapacitorDownloader } from '@capgo/capacitor-downloader';

await CapacitorDownloader.addListener('downloadProgress', ({ id, progress }) => {
  console.log(id, `${progress}%`);
});
await CapacitorDownloader.addListener('downloadCompleted', ({ id }) => {
  console.log(id, 'completed');
});
await CapacitorDownloader.addListener('downloadFailed', ({ id, error }) => {
  console.error(id, error);
});

await CapacitorDownloader.download({
  id: 'course-42',
  url: 'https://cdn.example.com/courses/42.zip',
  destination: 'courses/42.zip',
  headers: { Authorization: 'Bearer <token>' },
  network: 'wifi-only',
  priority: 'normal',
  notification: 'progress', // Android: remove the system notification when done
});

// Later
await CapacitorDownloader.pause({ id: 'course-42' });
await CapacitorDownloader.resume({ id: 'course-42' });
const status = await CapacitorDownloader.checkStatus({ id: 'course-42' });
console.log(status.state, status.progress);

Un chemin relatif destination résout vers le répertoire Documents de l’app sur iOS et le répertoire de fichiers externes spécifique à l’app sur Android. Vous pouvez également passer un chemin absolu ou un file:// URL. Utilisez getFileInfo({ path }) pour lire la taille et le type MIME après le téléchargement, et stop({ id }) pour annuler et supprimer les données partielles.

Migration depuis cordova-plugin-file-transfer

Télécharger

// Before
const ft = new FileTransfer();
ft.onprogress = (e) => e.lengthComputable && setProgress(e.loaded / e.total);
ft.download(
  encodeURI(url),
  cordova.file.dataDirectory + 'report.pdf',
  (entry) => console.log(entry.toURL()),
  (err) => console.error(err.code, err.http_status),
  false,
  { headers: { Authorization: 'Bearer <token>' } },
);
// After
const { uri } = await Filesystem.getUri({ directory: Directory.Data, path: 'report.pdf' });
await FileTransfer.downloadFile({
  url,
  path: uri,
  progress: true,
  headers: { Authorization: 'Bearer <token>' },
});

Envoyer

// Before
const options = new FileUploadOptions();
options.fileKey = 'file';
options.fileName = 'photo.jpg';
options.mimeType = 'image/jpeg';
options.params = { albumId: '7' };
options.headers = { Authorization: 'Bearer <token>' };
new FileTransfer().upload(fileUrl, encodeURI(serverUrl), onSuccess, onError, options);
// After, foreground
await FileTransfer.uploadFile({
  url: serverUrl,
  path: fileUrl,
  fileKey: 'file',
  mimeType: 'image/jpeg',
  params: { albumId: '7' },
  headers: { Authorization: 'Bearer <token>' },
});

// After, background
await Uploader.startUpload({
  filePath: fileUrl,
  serverUrl,
  uploadType: 'multipart',
  fileField: 'file',
  parameters: { albumId: '7' },
  headers: { Authorization: 'Bearer <token>' },
});

Notez que params dans @capacitor/file-transfer sont des paramètres de requête URL. Si votre serveur attend des champs de formulaire, utilisez l’uploader Capgo parameters, qui sont envoyés comme champs de formulaire multipart.

Table de correspondance

cordova-plugin-file-transfer @capacitor/file-transfer Plugins Capgo
download(source, target, ...) downloadFile({ url, path }) CapacitorDownloader.download({ id, url, destination })
upload(file, server, ...) uploadFile({ url, path }) Uploader.startUpload({ filePath, serverUrl })
onprogress addListener('progress') addListener('events') / addListener('downloadProgress')
abort() non disponible removeUpload({ id }) / stop({ id })
options.fileKey fileKey fileField ou files[].fieldName
options.params params (chaîne de requête) parameters (champs de formulaire)
options.httpMethod method method (POST ou PUT)
options.chunkedMode chunkedMode Géré nativement
cordova.file.dataDirectory Filesystem.getUri({ directory: Directory.Data }) Chemin relatif ou file:// URL
FileTransferError.http_status error.data.httpStatus event.payload.statusCode

Les chemins : l'élément qui bloque les migrations

Cordova code transmet cdvfile:// ou cordova.file.* partout. Dans Capacitor :

  • Récupérez les chemins natifs depuis Filesystem.getUri() ou depuis le plugin qui a créé le fichier (caméra, sélecteur de fichiers, enregistreur).
  • Pour afficher une image téléchargée dans le WebView, convertissez le chemin natif avec Capacitor.convertFileSrc(path).
  • Capgo dispose d'un plugin fichier et une file picker si @capacitor/filesystem ne couvre pas votre cas.

Troubleshooting

L'upload fonctionne sur Android mais échoue sur iOS avec une erreur de fichier introuvable. Vous avez transmis une capacitor:// URL WebView au lieu d’un chemin natif file:// . Utilisez le chemin fourni par Filesystem.getUri().

Le serveur refuse l’upload avec un code 415. Incohérence entre multipart et corps brut. Pour les URLs présignées, utilisez PUT avec un explicite Content-Type.

Les uploads en arrière-plan s'arrêtent sur iOS. L'utilisateur a quitté l'app de force, ce qui annule les sessions en arrière-plan, ou fetch le mode arrière-plan est absent quand vous en avez besoin.

Android affiche une notification de téléchargement bloquée. Définissez notification: 'progress' ou 'hidden' sur le downloader.

Crash mémoire lors de gros téléchargements. Vous utilisez encore fetch ou la lecture du fichier en base64 via le bridge. Passez à un téléchargement natif sur le disque.

Lancez la migration

Remplacer des plugins natifs nécessite un nouveau build pour les stores, ce qui Build Capgo peut s'exécuter dans le cloud pour iOS et Android. Ensuite, le JavaScript qui gère les uploads et les downloads peut être corrigé et amélioré avec les live updates Capgo. Pour le reste de la migration de Cordova vers Capacitor, consultez notre guide de migration, et pour les autres SDK natifs payants ou hérités, les alternatives aux plugins Ionic Enterprise.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.