【问题标题】:How can I save a downloaded file with Capacitor in Ionic4 Angular?如何在 Ionic4 Angular 中使用 Capacitor 保存下载的文件?
【发布时间】:2019-10-31 19:21:56
【问题描述】:

我最近将我的 Ionic 4 Angular 应用程序发布为网络应用程序和原生 Android 应用程序。
在原生 Android 应用中,一切正常,除了保存下载的文件。

要下载和保存文件,我一直使用file-saver npm 包,如下所示(这是我每次必须下载东西时调用的共享服务,从 PDF 到图像等... ):

import { saveAs } from 'file-saver';

// ...

saveGenericFile(api: string, fileinfos: any, idFile: string): any {
    let mediaType = 'application/pdf';
    let fileName = '';

    if (fileinfos != null) {
      mediaType = fileinfos.contentType;
      fileName = fileinfos.fileName;
    }

    const headers = this.base.commonHeader;
    const url = this.baseUrl + api + '?id=' + idFile;
    this.http.post(url, null, { headers, responseType: 'blob' }).subscribe(
      (response) => {
        // tslint:disable-next-line: prefer-const
        let blob = new Blob([response], { type: mediaType });
        saveAs(blob, fileName);
      }, e => {
        console.error(e);
        this.toastsvc.generateToast('ERROR! An error occurred while saving this File, try later or contact support', 'danger');
      }, () => {
        /* do nothing */
      }
    );
  }

正如我上面所说,这段代码 sn-p 工作正常,但只是当我必须从网络版本中保存一些东西时。

我能找到的唯一在线示例都是关于 Cordova 和/或以前/已弃用的版本。
关于电容器,我刚刚找到了this documentation,并从中找到了这段代码sn-p:

import { Plugins, FilesystemDirectory, FilesystemEncoding } from '@capacitor/core';

const { Filesystem } = Plugins;

fileWrite() {
  try {
    Filesystem.writeFile({
      path: 'secrets/text.txt',
      data: "This is a test",
      directory: FilesystemDirectory.Documents,
      encoding: FilesystemEncoding.UTF8
    });
  } catch(e) {
    console.error('Unable to write file', e);
  }
}

但问题是我上面的函数返回一个 blob,而这个函数只接受一个字符串作为数据。

那么,是否有任何 Capacitor-Native 等效功能可用于在作为 Web 应用程序和 Android 本机应用程序运行时下载(和保存)Blob 文件?


更新

我也尝试了以下方法,但它不起作用:

saveGenericFile(api: string, fileinfos: any, gidFile: string): any {
    let mediaType = 'application/pdf';
    let fileName = '';

    if (fileinfos != null) {
      mediaType = fileinfos.contentType;
      fileName = fileinfos.fileName;
    }

    const headers = this.base.commonHeader;
    const url = this.baseUrl + api + '?id=' + gidFile;
    this.http.post(url, null, { headers, responseType: 'blob' }).subscribe(
      (response) => {
        if (!this.useCordovaDl) {
          // tslint:disable-next-line: prefer-const
          let blob = new Blob([response], { type: mediaType });
          saveAs(blob, fileName);
        } else {
          this.blobFileWrite(fileName, response);
        }
      }, e => {
        console.error(e);
        this.toastsvc.generateToast('ERROR! An error occurred while saving this File, try later or contact support', 'danger');
      }, () => {
        /* do nothing */
      }
    );
  }

  blobFileWrite(filename: string, blobfile: Blob) {
    const reader = new FileReader();

    // This fires after the blob has been read/loaded.
    reader.addEventListener('loadend', (e: any) => {
      const text = e.srcElement.result;
      this.fileWrite(filename, text);
    });

    // Start reading the blob as text.
    reader.readAsText(blobfile);
  }

  fileWrite(filename: string, filedata: string) {
    try {
      Filesystem.writeFile({
        path: filename,
        data: filedata
        // ,
        // directory: FilesystemDirectory.Documents,
        // encoding: FilesystemEncoding.UTF8
      });
    } catch (e) {
      console.error('Unable to write file', e);
    }
  }

更新 #2

看起来像there's still an opened issue on GitHub 关于使用 Capacitor 保存 Blob 数据。同时,我将寻找 Cordova 解决方案。或者,如果平台是 android 或 ios,我将简单地禁用每个下载按钮。
如果我能找到一个,我会在此处发布所有可用的 Cordova 解决方法

【问题讨论】:

  • 使用 FileReader 可以工作,除非您安装了 cordova-plugin-file 并使用 angular,因为 angular 的 zonejs 会导致阻止 FileReader 工作的错误
  • @jcesarmobile 您好,感谢您的评论!实际上,我将 Ionic 4 与 Angular 7 一起使用,所以这可以解释为什么 FileReader 不起作用。有没有关于这个的github问题?
  • 是的github.com/ionic-team/capacitor/issues/1564,见最后一条评论,它有一个解决方法的链接
  • 只是想插话说电容器社区 HTTP 插件会下载文件:github.com/capacitor-community/http
  • 嗨@ingage,感谢您的评论!不知道那个repo,我一定会试一试

标签: typescript ionic-framework ionic4 capacitor


【解决方案1】:

如果你想要实现的是将文件保存在文件系统中,你可以用字符串base64将它保存到文件系统中

image = "data:image/png;base64,iVBORw0KGgo... bla bla bla"
Capacitor.Plugins.Filesystem.appendFile({
    data:image,
    path:"directory/image.png",
    directory:"DOCUMENTS"
}).then(c=>{console.log("se escribiooo")})

它在您的文件系统中生成图像(我刚刚在 android 模拟器中尝试了此代码),只需使用方法 appendFile 代替 writeFile,并使用 base64 代替 blob,如果您只有 blob,则只需将其转换为 base64

【讨论】:

    【解决方案2】:

    与您分享我的解决方法。

    我正在使用文件系统插件的网络实现。 不知道这是否是一个好的解决方案,但它有助于解决我的问题。

    import { FilesystemDirectory, FilesystemEncoding } from '@capacitor/core'
    // const { Filesystem } = Plugins // => Doesn't work with blob in native
    // Workaround: Use Web-Implementation of plugin
    import { FilesystemPluginWeb } from '@capacitor/core/dist/esm/web/filesystem.js'
    const Filesystem = new FilesystemPluginWeb()
    

    【讨论】:

      【解决方案3】:

      您可以创建一个插件,您可以将 URL 传递给该插件,它会在本地下载。正如您已经发现传递 blob/文件是不可能的,但是。

      如果没有可用的插件或者您不想创建一个。 您可以从js 调用本机函数,您可以在native 侧监听 URL 等。

      【讨论】:

      • 由于期限短和预算低的原因,我在Plaform 上添加了一个检查:如果是androidios,而不是如上所示下载,我只是打开一个外部从浏览器下载文件的浏览器窗口
      • 这也是个不错的方法!
      • @Deadpool,我刚刚听了你的评论(我遇到了同样的问题)你还有没有办法解决如何在外部浏览器中打开内部文件进行下载?谢谢
      • 嗨@DanyY 对不起,如果我迟到了,但我在这几个月里并没有经常使用 SO。顺便说一句,不幸的是我去年换了工作,我再也无法访问我的旧项目了。如果我提醒正确,我在服务器端使用 GET 来返回要下载的文件,在客户端我只是使用 window.open('api url that returns file' + fileId, '_blank');'_blank' 重载,应该在新窗口中打开文件。我不记得我是使用默认窗口还是从cordova 导入的。很抱歉,但我希望这对您有所帮助,让我知道它是否有效
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-07
      • 2019-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      相关资源
      最近更新 更多