如何在Ember.js中使用Capacitor的downloadFile?原生端报错排查
Ember.js + Capacitor 文件下载原生端报错排查与路径配置指南
问题背景
使用Ember.js开发组件实现文件下载功能,基于Capacitor工具开发。Web应用运行正常,但原生应用触发下载时,Xcode抛出错误:
[error] - {"errorMessage":"Unable to download file","message":"Unable to download file","code":"DOWNLOAD"}
组件代码路径:/components/component.js
import Component from '@glimmer/component'; import { action } from '@ember/object'; import { Plugins, FilesystemDirectory, CapacitorHttp, Diretory } from '@capacitor/core'; import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; import { Http } from '@capacitor-community/http' export default class ExportLink extends Component { @action async onClick() { this.isRequesting = true; try { // Fetch the download url, since a download has no Authentication information const urlResponse = await this.store .fetch('signed_urls', { type: 'post', body: { request_url: this.requestUrl } }); const options = { url: urlResponse.url, filePath: `${this.fileName}.${this.args.extension}`, fileDirectory: Directory.Documents, }; const response = await Http.downloadFile(options); const blob = await response.blob; const downloadResponse = new Response(blob, { status: response.status, headers: (new Headers(response.headers)) }) if (!downloadResponse.ok) { throw downloadResponse.statusText } // create a new download link. Add the content of the download, so the download prompt is immediatly invoked const link = document.createElement('a'); const objectUrl = URL.createObjectURL(blob); link.setAttribute('href', objectUrl); link.setAttribute('download', `${this.fileName}.${this.args.extension}`); link.setAttribute('rel', 'noopener noreferrer'); link.setAttribute('target', '_blank'); // fallback if a direct download isnt supported link.dispatchEvent(new MouseEvent('click')); URL.revokeObjectURL(objectUrl); } catch(e) { console.error({e: e}); this.notifications.add(this.intl.t('general.forms.unknown_error'), { type: 'warning' }); } finally { this.isRequesting = false; } return false; } }
错误排查与修复
1. 冗余导入与拼写错误
代码中存在重复导入和拼写错误,会干扰Capacitor API的正常调用:
- 删除冗余导入行:
import { Plugins, FilesystemDirectory, CapacitorHttp, Diretory } from '@capacitor/core';(已单独导入Filesystem和Directory,且Diretory存在拼写错误) - 确保仅保留必要导入:
import { Filesystem, Directory } from '@capacitor/filesystem';和import { Http } from '@capacitor-community/http'
2. 原生端与Web端处理逻辑差异
Capacitor的Http.downloadFile在原生端直接将文件保存到指定目录,不会返回blob对象,原代码中response.blob的逻辑仅适用于Web端,这是导致原生报错的核心原因:
修改后的核心处理逻辑:
// 替换原response处理代码 const response = await Http.downloadFile(options); if (response.status !== 200) { throw new Error('下载请求失败'); } // 区分原生/Web环境处理 if (Capacitor.isNativePlatform()) { // 原生端:获取文件URI并触发系统打开/分享 const fileUri = await Filesystem.getUri({ path: options.filePath, directory: options.fileDirectory }); // 调用Share插件让用户选择打开方式 await Plugins.Share.share({ url: fileUri.uri }); } else { // Web端:保留原blob下载逻辑 const blob = await response.blob; const downloadResponse = new Response(blob, { status: response.status, headers: new Headers(response.headers) }); if (!downloadResponse.ok) { throw downloadResponse.statusText; } const link = document.createElement('a'); const objectUrl = URL.createObjectURL(blob); link.setAttribute('href', objectUrl); link.setAttribute('download', `${this.fileName}.${this.args.extension}`); link.setAttribute('rel', 'noopener noreferrer'); link.dispatchEvent(new MouseEvent('click')); URL.revokeObjectURL(objectUrl); }
3. 原生平台权限配置
iOS和Android需配置文件访问权限,否则会因权限不足导致下载失败:
- iOS:在
Info.plist中添加NSDocumentsFolderUsageDescription,填写访问文档目录的用途说明(如"需要访问文档目录保存下载文件") - Android:在
AndroidManifest.xml中添加权限(Android 13+可使用更细粒度权限):<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
附加问题:Android/iOS端filePath设置规范及与报错的关联
正确设置方式
- iOS:
- 直接写文件名:如
filePath: 'report.pdf',文件会保存到Documents根目录 - 子目录路径:如
filePath: 'exports/report.pdf',需提前用Filesystem.mkdir创建exports目录
- 直接写文件名:如
- Android:
- 直接写文件名:文件保存到
内部存储/Documents目录 - 子目录路径:如
filePath: 'my_app/report.xlsx',同样需提前创建子目录
- 直接写文件名:文件保存到
与当前报错的关联
如果filePath指定的子目录不存在且未提前创建,会导致Capacitor无法写入文件,触发DOWNLOAD错误。确保路径中的目录已创建,或直接使用根文件名即可避免此类问题。
内容的提问来源于stack exchange,提问作者Mikelemuel
相关产品推荐
相关产品推荐

