Capacitor アプリに最適な cordova-plugin-file-transfer の代替手段は、1つの問いで決まります。転送がアプリのバックグラウンド移行後も継続する必要があるかどうかです。進捗表示付きの通常のアップロードやダウンロードには、公式の @capacitor/file-transfer プラグイン。大きなファイル、不安定なネットワーク、ユーザーがアプリを切り替えても転送を続ける必要がある場合は、 @capgo/capacitor-uploader と @capgo/capacitor-downloader、これらはネイティブのバックグラウンド転送APIで動作します。本ガイドではこれらを比較し、すべての FileTransfer コールを使用してください。
cordova-plugin-file-transfer はまだ非推奨のままですか?
経緯がややこしいので、事実を整理します:
- 2017年に Apache Cordova チームはこのプラグインを非推奨にする計画を発表し、開発者に
XMLHttpRequestLevel 2 を推奨しました。 - このプラグインが npm で非推奨としてマークされたことはありません。バージョン2.0.0 は2023年9月、2.0.1 は2026年8月にリリースされました。GitHub リポジトリは現在もアクティブです。
つまり、廃止されたわけではありません。ただし Capacitor アプリでは、依然として次のような Cordova プラグインです:
- に依存し、
cordova-plugin-fileとそのcdvfile://とfile://パスモデル、 - は Capacitor の
Filesystemディレクトリと URI 変換、 - バックグラウンド転送に対応していません、
- コールバックスタイルの API を使用します。
Cordova から移行する場合、ネイティブの Capacitor プラグインに置き換えることで、維持する最後の理由の一つを解消できます cordova-plugin-file.
「fetch を使えばいい」が大きなファイルで壊れる理由
Apache が推奨する代替手段である XHR は、小さな JSON や画像には機能します。しかし、ハイブリッドアプリでの実際のファイル転送には失敗します:
- メモリ。
fetchおよび XHR は WebView 内でBlobまたはArrayBufferを消費します。500 MB の動画は WebView メモリで 500 MB を占め、さらにブリッジ経由で書き込むためのコピーが発生します。ミッドレンジの Android デバイスでは、これによりレンダラーがクラッシュします。 - サスペンド ユーザーがアプリを切り替えると、iOSはWebViewをサスペンドします。その際、実行中のリクエストは停止または失敗します。
- OS連携なし システムのダウンロード通知、Wi-Fi限定オプション、接続断後のレジュームはありません。
ネイティブプラグインはディスクとネットワーク間を直接ストリーミングし、JavaScriptをデータパスから排除します。
オプション比較
| 要件 | cordova-plugin-file-transfer | @capacitor/file-transfer | @capgo/capacitor-uploader | @capgo/capacitor-downloader |
|---|---|---|---|---|
| ディスクへのダウンロード | はい | はい | いいえ | はい |
| ディスクからアップロード | はい | はい | はい | いいえ |
| 進捗イベント | はい | はい (progress listener) |
はい (events) |
はい (downloadProgress) |
| Multipart form data | はい | はい(デフォルト) | はい | なし |
| Raw binary PUT(presigned URL) | はい | はい(設定 Content-Type) |
はい (uploadType: 'binary') |
なし |
| 1回のリクエストで複数ファイル | いいえ | いいえ | はい (files) |
なし |
| キャンセル | abort() |
いいえ | removeUpload |
stop |
| 一時停止 / 再開 | いいえ | いいえ | いいえ | pause, resume |
| リトライ | いいえ | いいえ | maxRetries |
いいえ |
| バックグラウンドで継続 | いいえ | アプリがアクティブな間 | はい | はい |
| Wi-Fi のみ | いいえ | いいえ | いいえ | network: 'wifi-only' |
| HTTPエラーの詳細 | http_status, body |
httpStatus, body |
イベント内のステータス code | イベント内のエラー文字列 |
| Web実装 | いいえ | はい | はい(fetchベース) | いいえ |
ほとんどのアプリが採用するのは @capacitor/file-transfer ユーザーに表示される小規模な転送にはこれを使い、メディアのアップロードキューやオフラインコンテンツのダウンロードには Capgo プラグインを使う構成です。
オプション 1: @capacitor/file-transfer
bun add @capacitor/file-transfer @capacitor/filesystem
bunx cap sync
このプラグインには完全なネイティブパスが必要です。以下から取得してください。 @capacitor/filesystem.
ダウンロード
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();
}
}
アップロード
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);
}
アップロードはデフォルトでマルチパート形式です。プレサインされた S3 URL などの生ストリームに送信する場合は、 method: 'PUT' と明示的な Content-Type ヘッダー(例: application/octet-stream.
エラーコードは OS-PLUG-FLTR-XXXX 形式に従います。主なものは: 0007 ファイルが見つかりません、 0008 接続に失敗しました、 0010 HTTP エラーステータスと httpStatus と body における error.data.
オプション2: @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
});
プリサインドURLには、 method: 'PUT'を使用します。デフォルトではバイナリボディになります:
await Uploader.startUpload({
filePath,
serverUrl: presignedUrl,
method: 'PUT',
headers: { 'Content-Type': 'video/mp4' },
mimeType: 'video/mp4',
});
1つのマルチパートリクエストで複数のファイルを:
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>' },
});
でキャンセル Uploader.removeUpload({ id }).
なぜイベントをACKするのか? 完了と失敗のイベントは永続的なネイティブキャッシュに保存されるため、アプリが処理する前に閉じられたりバックグラウンドに移行したりした場合でも再配信できます。ACKを行うとイベントが削除され、プラグインが次に初期化されたときに再ブロードキャストされなくなります。
iOSのセットアップ。 アップローダーはバックグラウンドの URLSessionを使用します。多くのアプリでは追加のセットアップは不要です。アプリがサスペンドされた後もアップロードを継続する必要がある場合は、 fetch まで UIBackgroundModes. 追加しないでください processing 。ただし、他の機能が使用している場合を除きます BGTaskScheduler。なぜなら、App Store Connect は、それを使用せずに宣言するビルドを拒否するためです BGTaskSchedulerPermittedIdentifiers.
オプション 3: @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);
相対パスは destination iOS ではアプリの Documents ディレクトリ、Android ではアプリ固有の外部ファイルディレクトリに解決されます。絶対パスまたは file:// URL。使用 getFileInfo({ path }) して、ダウンロード後のサイズと MIME タイプを読み取り、 stop({ id }) キャンセルし、部分データを削除します。
cordova-plugin-file-transfer からの移行
ダウンロード
// 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>' },
});
アップロード
// 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>' },
});
注意してください params における @capacitor/file-transfer は URL クエリパラメータです。サーバーがフォームフィールドを期待している場合は、Capgo アップローダーの parametersを使用します。これらはマルチパートフォームフィールドとして送信されます。
マッピングテーブル
| cordova-plugin-file-transfer | @capacitor/file-transfer | 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() |
利用不可 | removeUpload({ id }) / stop({ id }) |
options.fileKey |
fileKey |
fileField または files[].fieldName |
options.params |
params (クエリ文字列) |
parameters (フォームフィールド) |
options.httpMethod |
method |
method (POST または PUT) |
options.chunkedMode |
chunkedMode |
ネイティブで処理 |
cordova.file.dataDirectory |
Filesystem.getUri({ directory: Directory.Data }) |
相対パスまたは file:// URL |
FileTransferError.http_status |
error.data.httpStatus |
event.payload.statusCode |
パス:マイグレーションが壊れる原因
Cordova code は cdvfile:// または cordova.file.* どこでもパスを渡します。Capacitor では:
- ネイティブパスを取得
Filesystem.getUri()ファイルを作成したプラグイン(カメラ、ファイルピッカー、レコーダーなど)から取得します。 - WebView でダウンロードした画像を表示するには、ネイティブパスを以下で変換します
Capacitor.convertFileSrc(path). - Capgo には ファイルプラグイン と ファイルピッカー もし
@capacitor/filesystemあなたのケースには対応していません。
トラブルシューティング
アップロードは Android で動作しますが、iOS ではファイルが見つからないエラーで失敗します。 ネイティブの capacitor:// パスではなく WebView URL を渡しました。 file:// のパスを使用してください。 Filesystem.getUri().
サーバーが 415 でアップロードを拒否します。 Multipart と raw body の不一致です。プリサイン URL では PUT を明示的に使用してください。 Content-Type.
iOS でバックグラウンドアップロードが停止します。 ユーザーがアプリを強制終了してバックグラウンドセッションがキャンセルされた場合、または fetch 必要なときにバックグラウンドモードが欠けている場合。
Androidでダウンロード通知が停止したままになる。 設定 notification: 'progress' または 'hidden' ダウンローダー上で。
大規模なダウンロード時のメモリクラッシュ。 まだ fetch を使用しているか、ブリッジ経由でファイルをbase64として読み取っている。ディスクへのネイティブダウンロードに切り替えてください。
マイグレーションをリリースする
ネイティブプラグインの入れ替えには新しいストアビルドが必要で、それは Capgo のビルド iOSとAndroid向けにクラウドで実行できます。その後、アップロードとダウンロードを担うJavaScriptは、次の方法で修正・改善できます。 Capgo Live UpdatesCordovaから Capacitor への移行の残りについては、こちらをご覧ください。 移行ガイドまた、その他の有料またはレガシーなネイティブSDKについては Ionic Enterpriseプラグインの代替案.