メインコンテンツへスキップ

Capacitorにおけるcordova-plugin-file-transferの代替手段

Capacitor アプリで cordova-plugin-file-transfer を置き換える:シンプルな転送には @capacitor/file-transfer、バックグラウンドジョブには Capgo のアップローダーとダウンローダーを使用。

Cordova アプリを Capacitor に移行するイラスト(ファイル転送プラグインガイド用)

Capacitor アプリに最適な cordova-plugin-file-transfer の代替手段は、1つの問いで決まります。転送がアプリのバックグラウンド移行後も継続する必要があるかどうかです。進捗表示付きの通常のアップロードやダウンロードには、公式の @capacitor/file-transfer プラグイン。大きなファイル、不安定なネットワーク、ユーザーがアプリを切り替えても転送を続ける必要がある場合は、 @capgo/capacitor-uploader と @capgo/capacitor-downloader、これらはネイティブのバックグラウンド転送APIで動作します。本ガイドではこれらを比較し、すべての FileTransfer コールを使用してください。

cordova-plugin-file-transfer はまだ非推奨のままですか?

経緯がややこしいので、事実を整理します:

  • 2017年に Apache Cordova チームはこのプラグインを非推奨にする計画を発表し、開発者に XMLHttpRequest Level 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プラグインの代替案.

Capacitor アプリ向けの Live Updates

Web レイヤーのバグが本番で発生したら、App Store の審査を何日も待たずに Capgo で修正を配信しましょう。ネイティブの変更は通常の審査フローに残したまま、ユーザーはバックグラウンドでアップデートを受け取れます。

最新のブログ記事

Capgoは、真にプロフェッショナルなモバイルアプリを作るために必要な最高のインサイトを提供します。