網站搜尋

typescript - 我如何在 Ionic4 Angular 中使用 Capacitor 保存已下載的文件?


我最近將我的 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 */
      }
    );
  }

如我上面所說,這段程式碼運作正常,但只是當我必須從網頁釋出中保存某些東西時。

我能找到的唯一線上範例都是關於 Cordova 和/或舊版/已棄用的版本。
關於 Capacitor,我只找到這份文件,並從中找到這個程式碼片段:

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

但問題是,我上面的函數返回的是一個二進位大物件,而這個函數只接受字串作為資料。

那麼,是否有任何 Capacitor-Native 的對應功能可以讓我在作為網頁應用程式運行以及作為 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

看起來 GitHub 上仍然有關於使用 Capacitor 保存 Blob 數據的未解決問題。與此同時,我會尋找 Cordova 的解決方案。或者,如果平台是 Android 或 iOS,我將直接禁用所有下載按鈕。
如果我能找到任何有效的 Cordova 變通方法,我會在這裡貼出來

答案#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")})

它在你的文件系統中生成圖片(我剛在安卓模擬器中試過這段程式碼),只需使用 appendFile 方法而不是 writeFile,並使用 base64 而非 blob,如果你只有 blob,你只需要將它轉換成 base64

答案#2

和你分享我的應對方法。

我正在使用 Filesystem 插件的網頁實現。不知道這是否是個好方法,但它有助於解決我的問題。

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()