Langsung ke konten utama

Alternatif cordova-plugin-file-transfer untuk Capacitor

Ganti cordova-plugin-file-transfer di aplikasi Capacitor: @capacitor/file-transfer untuk transfer sederhana, Capgo uploader dan downloader untuk background job.

Ilustrasi migrasi aplikasi Cordova ke Capacitor, digunakan untuk panduan plugin transfer file

Alternatif terbaik untuk cordova-plugin-file-transfer pada aplikasi Capacitor bergantung pada satu pertanyaan: apakah transfer perlu bertahan saat aplikasi berpindah ke latar belakang? Untuk upload dan download normal dengan progress, gunakan @capacitor/file-transfer plugin resmi. Untuk file besar, jaringan tidak stabil, atau transfer yang harus terus berjalan saat pengguna berpindah aplikasi, gunakan @capgo/capacitor-uploader dan @capgo/capacitor-downloader, yang berjalan di atas API transfer latar belakang native. Panduan ini membandingkan keduanya dan memetakan setiap FileTransfer dipanggil.

Apakah cordova-plugin-file-transfer masih deprecated?

Sejarahnya membingungkan, jadi inilah faktanya:

  • Pada 2017, tim Apache Cordova mengumumkan rencana untuk mendeprekasi plugin ini dan mengarahkan developer ke XMLHttpRequest Level 2.
  • Plugin ini tidak pernah ditandai sebagai deprecated di npm. Versi 2.0.0 dirilis pada September 2023, dan 2.0.1 pada Agustus 2026. Repositori GitHub masih aktif.

Jadi, plugin ini tidak mati. Namun, dalam aplikasi Capacitor, ini tetap menjadi plugin Cordova yang:

  • bergantung pada cordova-plugin-file dan cdvfile:// dan file:// model path-nya,
  • tidak sesuai dengan Capacitor Filesystem direktori dan konversi URI,
  • tidak mendukung transfer background,
  • menggunakan API bergaya callback.

Jika Anda bermigrasi dari Cordova, menggantinya dengan plugin native Capacitor menghilangkan salah satu alasan terakhir untuk mempertahankan cordova-plugin-file.

Mengapa “just use fetch” gagal pada file besar

Pengganti yang disarankan Apache, XHR, berfungsi untuk JSON kecil dan gambar. Gagal untuk transfer file nyata di aplikasi hybrid:

  • Memori. fetch dan XHR memberi Anda Blob atau ArrayBuffer di WebView. Video 500 MB berarti 500 MB di memori WebView, lalu salinan untuk menulisnya melalui bridge. Di perangkat Android kelas menengah, itu membuat renderer crash.
  • Suspensi. Saat pengguna beralih aplikasi, iOS menangguhkan WebView. Permintaan yang sedang berjalan terhenti atau gagal.
  • Tidak ada integrasi OS. Tidak ada notifikasi unduhan sistem, tidak ada opsi hanya Wi-Fi, tidak bisa melanjutkan setelah koneksi terputus.

Plugin native melakukan streaming langsung antara disk dan jaringan, tanpa melibatkan JavaScript di jalur data.

Perbandingan opsi

Butuh cordova-plugin-file-transfer @capacitor/file-transfer @capgo/capacitor-uploader @capgo/capacitor-downloader
Unduh ke disk Ya Ya Tidak Ya
Upload dari disk Ya Ya Ya Tidak
Event progres Ya Ya (progress listener) Ya (events) Ya (downloadProgress)
Data formulir multipart Ya Ya (default) Ya n/a
PUT biner mentah (URL presigned) Ya Ya (set Content-Type) Ya (uploadType: 'binary') n/a
Berkas multiple dalam satu permintaan Tidak Tidak Ya (files) n/a
Batal abort() Tidak removeUpload stop
Jeda / lanjutkan Tidak Tidak Tidak pause, resume
Percobaan ulang Tidak Tidak maxRetries Tidak
Tetap berjalan di latar belakang Tidak Saat aplikasi aktif Ya Ya
Hanya Wi-Fi Tidak Tidak Tidak network: 'wifi-only'
Detail error HTTP http_status, body httpStatus, body Status code dalam event String error dalam event
Implementasi web Tidak Ya Ya (berbasis fetch) Tidak

Sebagian besar aplikasi akhirnya memakai @capacitor/file-transfer untuk transfer kecil yang terlihat oleh pengguna, dan plugin Capgo untuk antrean upload media serta unduhan konten offline.

Opsi 1: @capacitor/file-transfer

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

Plugin ini butuh path native lengkap. Dapatkan dari @capacitor/filesystem.

Unduh

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

Unggah

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

Upload secara default menggunakan multipart. Untuk raw stream, misalnya ke presigned S3 URL, atur method: 'PUT' dan yang eksplisit Content-Type header seperti application/octet-stream.

Kode error mengikuti OS-PLUG-FLTR-XXXX format. Berikut yang berguna: 0007 file tidak ditemukan, 0008 koneksi gagal, 0010 status error HTTP dengan httpStatus dan body di error.data.

Opsi 2: background upload dengan @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
});

Untuk presigned URLs, gunakan method: 'PUT', yang secara default menggunakan body biner:

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

Beberapa file dalam satu request 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>' },
});

Batalkan dengan Uploader.removeUpload({ id }).

Mengapa event harus di-acknowledge? Event yang selesai dan gagal disimpan di cache native yang persisten, sehingga dapat dikirim ulang jika aplikasi ditutup atau di-background sebelum event tersebut diproses. Meng-acknowledge akan menghapus event agar tidak disiarkan ulang saat plugin diinisialisasi berikutnya.

Setup iOS. Uploader menggunakan background URLSession. Banyak aplikasi tidak memerlukan setup tambahan. Jika upload harus berlanjut setelah aplikasi disuspend, tambahkan fetch ke UIBackgroundModes. Jangan tambahkan processing kecuali fitur lain menggunakannya BGTaskScheduler, karena App Store Connect menolak build yang mendeklarasikannya tanpa BGTaskSchedulerPermittedIdentifiers.

Opsi 3: background download dengan @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);

Path relatif destination merujuk ke direktori Documents aplikasi di iOS dan direktori file eksternal khusus aplikasi di Android. Anda juga dapat meneruskan path absolut atau file:// URL. Gunakan getFileInfo({ path }) untuk membaca ukuran dan tipe MIME setelah download, dan stop({ id }) untuk membatalkan dan menghapus data parsial.

Migrasi dari cordova-plugin-file-transfer

Unduh

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

Unggah

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

Perhatikan bahwa params di @capacitor/file-transfer adalah parameter query URL. Jika server Anda mengharapkan field form, gunakan uploader Capgo parameters, yang dikirim sebagai field form multipart.

Tabel pemetaan

cordova-plugin-file-transfer @capacitor/file-transfer Plugin 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() tidak tersedia removeUpload({ id }) / stop({ id })
options.fileKey fileKey fileField atau files[].fieldName
options.params params (query string) parameters (field form)
options.httpMethod method method (POST atau PUT)
options.chunkedMode chunkedMode Ditangani secara native
cordova.file.dataDirectory Filesystem.getUri({ directory: Directory.Data }) Path relatif atau file:// URL
FileTransferError.http_status error.data.httpStatus event.payload.statusCode

Path: bagian yang bikin migrasi gagal

Cordova code meneruskan cdvfile:// atau cordova.file.* path di mana-mana. Di Capacitor:

  • Dapatkan path native dari Filesystem.getUri() atau dari plugin yang membuat file (kamera, file picker, perekam).
  • Untuk menampilkan gambar yang diunduh di WebView, konversi path native dengan Capacitor.convertFileSrc(path).
  • Capgo memiliki plugin file dan pemilih file jika @capacitor/filesystem tidak mencakup kasus Anda.

Pemecahan Masalah

Upload berfungsi di Android tetapi gagal di iOS dengan error file not found. Anda mengirim capacitor:// URL WebView alih-alih native file:// path native. Gunakan path dari Filesystem.getUri().

Server menolak upload dengan 415. Ketidakcocokan multipart vs raw body. Untuk presigned URL gunakan PUT dengan eksplisit Content-Type.

Upload latar belakang berhenti di iOS. Pengguna memaksa keluar dari aplikasi, yang membatalkan sesi background, atau fetch mode background tidak tersedia saat Anda membutuhkannya.

Android menampilkan notifikasi download yang macet. Atur notification: 'progress' atau 'hidden' pada downloader.

Crash memori pada download besar. Anda masih menggunakan fetch atau membaca file sebagai base64 melalui bridge. Beralih ke download native ke disk.

Rilis migrasi

Mengganti plugin native butuh build store baru, yang Build Capgo bisa dijalankan di cloud untuk iOS dan Android. Setelah itu, JavaScript yang mengatur upload dan download bisa diperbaiki dan ditingkatkan dengan Live updates Capgo. Untuk sisa migrasi dari Cordova ke Capacitor, lihatlah panduan migrasikami, dan untuk SDK native berbayar atau legacy lainnya, Alternatif plugin Ionic Enterprise.

Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.