跳过主要内容

cordova-plugin-file-transfer Capacitor替代方案

替换cordova-plugin-file-transfer在Capacitor应用中:@capacitor/file-transfer用于简单的传输,Capgo上传器和下载器用于后台作业。

文章来源

马丁·多纳迪厄

作者

瓦莱里娅

审阅者

乔丹

编辑

cordova-plugin-file-transfer Alternative for Capacitor

一个Capacitor应用的最佳cordova-plugin-file-transfer替代方案取决于一个问题:传输是否需要在应用切换到后台时继续? @capacitor/file-transfer 对于正常的上传和下载,带有进度的使用官方 @capgo/capacitor-uploader and @capgo/capacitor-downloader本指南将比较并映射这些插件,帮助您选择合适的替代方案。 FileTransfer call.

是否 Cordova-plugin-file-transfer 还处于弃用状态?

历史混乱,所以这里是事实:

  • 2017 年,Apache Cordova 团队宣布计划弃用该插件并指向 XMLHttpRequest 级别 2。
  • The plugin was never flagged as deprecated on npm. Version 2.0.0 shipped in September 2023, and 2.0.1 in August 2026. The GitHub repository is active.

Capacitor 仓库仍然活跃。

  • 依赖于 cordova-plugin-file 依赖于 cdvfile:// 和其 file:// 和
  • 不符合Capacitor的 Filesystem 目录和URI转换
  • 没有后台传输支持
  • 使用回调样式API

如果您正在从Cordova迁移,使用nativeCapacitor插件替换它,会消除您保持 cordova-plugin-file.

为什么“只使用fetch”在大文件上会失败

Apache建议的替代方案,XHR,适用于小JSON和图片。它在混合应用中进行真正的文件传输工作时失败:

  • 内存。 fetch 或 Blob 在WebView中 ArrayBuffer 在WebView中500MB的视频意味着500MB的WebView内存,然后通过桥接写入。中档Android设备的渲染器会崩溃。
  • 暂停。 当用户切换应用时,iOS会暂停WebView。在飞行中的请求会卡住或失败。
  • 没有OS集成。 没有系统下载通知,没有Wi-Fi仅选项,没有断开连接后恢复。

原生插件直接在磁盘和网络之间流动,JavaScript被排除在数据路径之外。

比较的选项

需要 cordova-plugin-file-transfer @capacitor/文件传输 @capgo/capacitor-上传工具 @capgo/capacitor下载器
下载到磁盘 是 是 否 是
从磁盘上传 是 是 是 否
进度事件 是 是(progress 监听器) Yes (events) Yes (downloadProgress)
多部分表单数据 Yes 是 (默认) Yes 无
原始二进制 PUT (预签名 URL) Yes 是 (设置 Content-Type) Yes (uploadType: 'binary') 无
多个文件在一个请求中 否 否 是(files) n/a
取消 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',
});

多个文件在一个多部分请求中:

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

为什么确认事件? 已完成和失败的事件存储在一个持久的本机缓存中,因此它们可以在应用程序关闭或后台之前处理它们之前重新传递。如果确认事件,则会移除事件,因此下次插件初始化时不会重新广播。

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 应用程序的文档目录和 Android 应用程序的外部文件目录。您还可以传递一个绝对路径或一个 file:// 使用 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 In @capacitor/file-transfer 是 URL 查询参数。如果您的服务器期望表单字段,请使用 Capgo 上传器的 parameters,它们将以多部分表单字段发送。

映射表

cordova-plugin-file-transfer @capacitor/文件传输 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 中显示下载的图像,使用 __CAPGO_KEEP_0__ 将本地路径转换为 Capacitor.convertFileSrc(path).
  • Capgo 有一个 文件插件 and a 文件选择器 如果 @capacitor/filesystem 不适用于您的场景。

故障排除

Android 上的上传功能正常,但在 iOS 上会出现找不到文件的错误。 上传在 Android 上工作,但在 iOS 上失败,显示文件未找到错误。 capacitor:// 您传递了 file:// WebView URL 而不是一个本机 Filesystem.getUri().

路径。使用来自 服务器拒绝上传,返回 415。 PUT 多部分 vs raw 体积不匹配。对于预签名 URL 使用一个明确的 Content-Type.

iOS背景上传停止。 用户强制关闭了应用程序,这会取消背景会话,或者 fetch 背景模式在您需要它时缺失。

Android显示下载通知卡住。 设置 notification: 'progress' 或 'hidden' 在下载器上

iOS背景上传停止。 您仍然使用 fetch 或通过桥接读取文件作为base64。切换到本机下载到磁盘。

将迁移

交换本机插件需要一个新的商店构建,这 Capgo 构建 可以在 iOS 和 Android 中运行云端。 之后,驱动上传和下载的 JavaScript 可以通过 Capgo 实时更新. 对于 Cordova 的其余部分Capacitor 移动,请参见我们的 迁移指南,以及其他付费或遗留本机 SDK 的 Ionic 企业插件替代方案.

为 Capacitor 应用程序提供实时更新

当 web 层 bug 活跃时,通过 Capgo 将修复推送到应用程序,而不是等待几天的应用商店审批。用户在后台接收更新,而本机更改仍在正常审批路径中。

最新博客

Capgo为您提供创建专业移动应用所需的最佳见解