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
XMLHttpRequestle 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-fileet soncdvfile://etfile://modèle de chemin, - ne convient pas à Capacitor
Filesystemconversions 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.
fetchet XHR vous donnent unBlobouArrayBufferdans 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/filesystemne 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.