Zum Hauptinhalt springen

cordova-plugin-file-transfer-Alternative für Capacitor

Ersetze cordova-plugin-file-transfer in Capacitor Apps: @capacitor/file-transfer für einfache Transfers, Capgo Uploader und Downloader für Background-Jobs.

Illustration der Migration einer Cordova-App zu Capacitor für einen Guide zum File-Transfer-Plugin

Die beste Alternative zu cordova-plugin-file-transfer für eine Capacitor-App hängt von einer Frage ab: Muss der Transfer weiterlaufen, wenn die App in den Hintergrund geht? Für normale Uploads und Downloads mit Fortschrittsanzeige nutze das offizielle @capacitor/file-transfer Plugin. Für große Dateien, instabile Netzwerke oder Transfers, die auch beim App-Wechsel weiterlaufen müssen, verwende @capgo/capacitor-uploader und @capgo/capacitor-downloader, die auf nativen Background-Transfer-APIs laufen. Dieser Guide vergleicht sie und ordnet jeden FileTransfer Aufruf zu.

Ist cordova-plugin-file-transfer immer noch deprecated?

Die Historie ist verwirrend, deshalb hier die Fakten:

  • Im Jahr 2017 kündigte das Apache Cordova-Team an, das Plugin als deprecated zu markieren, und verwies Entwickler auf XMLHttpRequest Level 2.
  • Das Plugin wurde auf npm nie als deprecated markiert. Version 2.0.0 erschien im September 2023, 2.0.1 im August 2026. Das GitHub-Repository ist aktiv.

Es ist also nicht tot. Aber in einer Capacitor-App ist es immer noch ein Cordova-Plugin, das:

  • abhängt von cordova-plugin-file und dessen cdvfile:// und file:// Pfadmodell,
  • passt nicht zu Capacitor Filesystem Verzeichnisse und URI-Konvertierungen,
  • unterstützt keine Hintergrund-Transfers,
  • nutzt Callback-basierte APIs.

Wenn Sie von Cordova migrieren, ersetzt die Nutzung nativer Capacitor-Plugins einen der letzten Gründe, cordova-plugin-file.

Warum „einfach fetch nutzen“ bei großen Dateien scheitert

Der von Apache empfohlene Ersatz XHR funktioniert für kleine JSON-Daten und Bilder. Bei echten Datei-Transfers in einer Hybrid-App scheitert er:

  • Speicher. fetch und XHR liefern Ihnen ein Blob oder ArrayBuffer in der WebView. Ein 500-MB-Video bedeutet 500 MB WebView-Speicher, plus eine Kopie für die Übertragung über die Bridge. Auf Mittelklasse-Android-Geräten crasht dadurch der Renderer.
  • Suspension. Wechselt der Nutzer die App, suspendiert iOS die WebView. Laufende Requests stocken oder schlagen fehl.
  • Keine OS-Integration. Keine System-Download-Benachrichtigung, keine Option nur über WLAN, kein Fortsetzen nach Verbindungsabbruch.

Native Plugins streamen direkt zwischen Disk und Netzwerk und halten JavaScript aus dem Datenpfad heraus.

Die Optionen im Vergleich

Benötigt cordova-plugin-file-transfer @capacitor/file-transfer @capgo/capacitor-uploader @capgo/capacitor-downloader
Auf Disk herunterladen Ja Ja Nein Ja
Vom Datenträger hochladen Ja Ja Ja Nein
Progress-Events Ja Ja (progress listener) Ja (events) Ja (downloadProgress)
Multipart-Formdaten Ja Ja (Standard) Ja k. A.
Rohes binäres PUT (presigned URLs) Ja Ja (gesetzt Content-Type) Ja (uploadType: 'binary') k. A.
Mehrere Dateien in einer Anfrage Nein Nein Ja (files) k. A.
Abbrechen abort() Nein removeUpload stop
Pausieren / Fortsetzen Nein Nein Nein pause, resume
Wiederholungen Nein Nein maxRetries Nein
Läuft im Hintergrund weiter Nein Während die App aktiv ist Ja Ja
Nur über WLAN Nein Nein Nein network: 'wifi-only'
HTTP-Fehlerdetails http_status, body httpStatus, body Status code in Events Fehlerstring in Events
Web-Implementierung Nein Ja Ja (fetch-basiert) Nein

Die meisten Apps nutzen am Ende @capacitor/file-transfer für kleine, für Nutzer sichtbare Transfers und die Capgo Plugins für Media-Upload-Queues und Offline-Content-Downloads.

Option 1: @capacitor/file-transfer

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

Das Plugin benötigt einen vollständigen nativen Pfad. Holen Sie ihn von @capacitor/filesystem.

Download

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

Upload

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

Uploads sind standardmäßig multipart. Für einen Raw-Stream, z. B. zu einer presigned S3-URL, setze method: 'PUT' und einen expliziten Content-Type Header wie zum Beispiel application/octet-stream.

Fehlercodes folgen dem OS-PLUG-FLTR-XXXX Format. Die wichtigsten sind: 0007 Datei nicht gefunden, 0008 Verbindung fehlgeschlagen, 0010 HTTP-Fehlerstatus mit httpStatus und body in einem error.data.

Option 2: Background-Uploads mit @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
});

Für presigned URLs verwenden Sie method: 'PUT', standardmäßig mit binärem Body:

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

Mehrere Dateien in einer Multipart-Anfrage:

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

Abbrechen mit Uploader.removeUpload({ id }).

Warum Events bestätigen? Abgeschlossene und fehlgeschlagene Events werden in einem persistenten nativen Cache gespeichert, sodass sie erneut zugestellt werden können, wenn die App geschlossen oder in den Hintergrund versetzt wurde, bevor sie die Events verarbeitet hat. Das Bestätigen entfernt das Event, damit es bei der nächsten Initialisierung des Plugins nicht erneut gesendet wird.

iOS-Setup. Der Uploader nutzt eine Hintergrund- URLSession. Viele Apps benötigen kein extra Setup. Wenn Uploads weiterlaufen müssen, nachdem die App suspendiert wurde, füge fetch zu UIBackgroundModes. Nicht hinzufügen processing es sei denn, ein anderes Feature nutzt BGTaskScheduler, da App Store Connect Builds ablehnt, die es ohne Angabe deklarieren BGTaskSchedulerPermittedIdentifiers.

Option 3: Hintergrund-Downloads mit @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);

Ein relativer destination entspricht auf iOS dem Documents-Verzeichnis der App und auf Android dem app-spezifischen externen Files-Verzeichnis. Du kannst auch einen absoluten Pfad oder eine file:// URL hinzu. Nutze getFileInfo({ path }) um Größe und MIME-Typ nach dem Download zu lesen, und stop({ id }) um abgebrochene Daten zu stornieren und zu löschen.

Migration von cordova-plugin-file-transfer

Download

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

Upload

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

Beachte, dass params in einem @capacitor/file-transfer sind URL-Query-Parameter. Wenn Ihr Server Formularfelder erwartet, verwenden Sie den Capgo-Uploader parameters, die als multipart-Formularfelder gesendet werden.

Mapping-Tabelle

cordova-plugin-file-transfer @capacitor/file-transfer Capgo Plugins
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() nicht verfügbar removeUpload({ id }) / stop({ id })
options.fileKey fileKey fileField oder files[].fieldName
options.params params (Query-String) parameters (Formularfelder)
options.httpMethod method method (POST oder PUT)
options.chunkedMode chunkedMode Nativ verarbeitet
cordova.file.dataDirectory Filesystem.getUri({ directory: Directory.Data }) Relativer Pfad oder file:// URL
FileTransferError.http_status error.data.httpStatus event.payload.statusCode

Pfade: der Teil, der Migrationen kaputt macht

Cordova code übergibt cdvfile:// oder cordova.file.* Pfade überall. In Capacitor:

  • Native Pfade von Filesystem.getUri() oder vom Plugin, das die Datei erstellt hat (Kamera, Dateiauswahl, Recorder).
  • Um ein heruntergeladenes Bild im WebView anzuzeigen, konvertiere den nativen Pfad mit Capacitor.convertFileSrc(path).
  • Capgo hat ein File-Plugin und einen File Picker falls @capacitor/filesystem deinen Anwendungsfall nicht abdeckt.

Fehlerbehebung

Der Upload funktioniert auf Android, schlägt aber auf iOS mit einem 'File not found'-Fehler fehl. Du hast eine capacitor:// WebView-URL statt eines nativen file:// Pfads übergeben. Nutze den Pfad von Filesystem.getUri().

Der Server lehnt den Upload mit 415 ab. Mismatch zwischen Multipart und Raw Body. Nutze für Presigned URLs PUT mit einem expliziten Content-Type.

Background-Uploads brechen auf iOS ab. Der User hat die App zwangsbeendet, wodurch Background-Sessions abgebrochen werden, oder fetch der Background-Modus fehlt, wenn man ihn braucht.

Android zeigt eine hängende Download-Benachrichtigung. Setzen Sie notification: 'progress' oder 'hidden' beim Downloader.

Memory-Crash bei großen Downloads. Du nutzt immer noch fetch oder liest die Datei als Base64 über die Bridge. Nutze stattdessen einen nativen Download auf die Disk.

Migration ausliefern

Der Austausch nativer Plugins erfordert einen neuen Store-Build, was Capgo Build läuft in der Cloud für iOS und Android. Danach lassen sich die JavaScript-Logik für Uploads und Downloads beheben und verbessern mit Capgo Live Updates. Für den Rest des Wechsels von Cordova zu Capacitor siehe unsere Migrationsleitfaden, und für andere kostenpflichtige oder veraltete native SDKs die Ionic Enterprise Plugin-Alternativen.

Live-Updates für Capacitor-Apps

Wenn ein Bug im Web-Layer live ist, liefere den Fix über Capgo aus, statt Tage auf die App-Store-Freigabe zu warten. Nutzer bekommen das Update im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Neues aus unserem Blog

Capgo gibt dir die besten Insights, um eine wirklich professionelle Mobile App zu erstellen.