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
XMLHttpRequestLevel 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-filedancdvfile://danfile://model path-nya, - tidak sesuai dengan Capacitor
Filesystemdirektori 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.
fetchdan XHR memberi AndaBlobatauArrayBufferdi 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/filesystemtidak 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.