Capacitor writeFile - Saving pdf file is in invalid format

This works fine:

    // If content is Blob, convert it to Text
    let convertBlob;
    if (content instanceof Blob) {
        convertBlob = await content.text();
    }

    if (isPlatform('ios')) {
        await Filesystem.writeFile({
            path: filename,
            data: convertBlob ? convertBlob : content,
            directory: Directory.Cache,
            encoding: Encoding.UTF8,
        });

This helped me as well, thank you guys!

It’s incredible how a simple thing can be so difficult and time taking to find out how to deal with, so, to help others I’ll explain in details here my problem so others may find it helpful.

I wanted to load a PDF file from my local assets folder to capacitor FileOpener plugin but I found that I couldn’t just take the file out of the assets folder because capacitor can’t read those files as they are internal on the webview.

The solution I found to open the PDF from my local assets folder was to use some http client to download the file as a base64, then use capacitor Filesystem plugin to write a temporary file and send it to FileOpener plugin.

I used angular HttpClient. It’s important to note that you can’t add the Encoding to filesystem.

Here is the code:

    public async openFile() {
        const filepath: string = `assets/images/books/my-book.pdf`;
        this.openLocalFileOnFileOpener(filepath);
    }

    async openLocalFileOnFileOpener(filepath: string, contentType: string = 'application/pdf') {
        return this.httpClient.get(filepath, { responseType: 'arraybuffer' }).subscribe(async (response) => {
            //
            // Get base64 data
            const binaryData = new Uint8Array(response);

            let binary = '';
            const bytes = new Uint8Array(binaryData);
            const len = bytes.byteLength;
            for (let i = 0; i < len; i++) {
                binary += String.fromCharCode(bytes[i]);
            }

            const base64Data = window.btoa(binary);

            //
            // Create temporary file
            const { uri } = await Filesystem.writeFile({
                path: 'temp1.pdf',
                data: base64Data,
                directory: Directory.Cache,
            });

            //
            // Open file
            FileOpener.open({ filePath: uri, contentType: contentType });
        });
    }

sir please! i beg you! i’m having the same issue and i’m tired, i’ve tried to implement your code, but it seems you have a variable called fileOpener and i have no idea where it comes from (i’m a beginner developer) could you please explain to me how to implement it correctly?

try {
      Filesystem.writeFile({
        path: fileName,
        data: pdfBase64,
        directory: Directory.Documents
        // encoding: Encoding.UTF8
      }).then((writeFileResult) => {
        Filesystem.getUri({
            directory: Directory.Documents,
            path: fileName
        }).then((getUriResult) => {
            const path = getUriResult.uri;
            this.fileOpener.open(path, 'application/pdf')
            .then(() => console.log('File is opened'))
            .catch(error => console.log('Error openening file', error));
        }, (error) => {
            console.log(error);
        });
      });
    } catch (error) {
      console.error('Unable to write file', error);
    }

line 13. Thanks! (Sorry if there are spelling errors, English is not my native language.)

I still have the same error, it tells me that the file is damaged when opening the excel with the android application. This only happens when I save it with writeFile, because if I transfer the file that is in s3 to the phone and open it originally, it opens correctly

import { FileOpener } from '@capacitor-community/file-opener';
import { Directory, Filesystem,Encoding,   } from '@capacitor/filesystem';

interface CustomFile {
  title: string,
  url: string,
  mineType: string
}
const openLink = async (file: CustomFile) => {
  try {
    const response = await fetch(file.url);
    const blob = await response.blob();
    const base64data = await convertBlobToBase64(blob)
    
    const savedFile = await Filesystem.writeFile({
        path: file.title,
        data: base64data,
        directory: Directory.Documents,
        // encoding: Encoding.UTF8,
        // recursive: true
      });
       await FileOpener.open({
         filePath: savedFile.uri,
         contentType: file.mineType,
       })
 
  } catch (error) {
    console.error(error);
  }
};


const convertBlobToBase64 = (blob: Blob) : Promise<string> => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = reject;
    reader.onload = () => {
        resolve(reader.result as string)
    }
    reader.readAsDataURL(blob);
})

openLink({
  title: 'gestion_0HV9WdBxQ1.xlsx',
  url: 'https://laguagua-bucket-br.s3.sa-east-1.amazonaws.com/informes/items/gestion_0HV9WdBxQ1.xlsx',
  mineType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});

Excel App Mobile message:

We have encountered a problem with some of the content of “gestion_0HV9WdBxQ1.xlsx”. Do you want us to try to recover as much as possible? If you trust the origin of this book, click yes

and something strange happens, that file is saved in my documents obviously on my android phone. What I do to test that file is search for it and then I try to send it to myself by WhatsApp and WhatsApp tells me “the selected file was not a document.” To test another case, I located that file written by FilesystemwriteFile and took it to my computer to open it with Microsoft Excel Online and when I try to open it it throws an error

{
“mistake”: {
“code”: 400,
“message”: “Conversion of the uploaded content to the requested output type is not supported.”,
“errors”: [
{
“message”: “Conversion of the uploaded content to the requested output type is not supported.”,
“domain”: “global”,
“reason”: “conversionUnsupportedConversionPath”
}
]
}
}

Same problem. I am trying to write pdf file on android


my code is:

        const url = "https://pdfobject.com/pdf/sample.pdf"
        const fileName = "test.pdf"
		try {
			const response = await fetch(url);
			const blob = await response.blob();

			const base64: string = await new Promise((resolve, reject) => {
				const reader = new FileReader();
				reader.onerror = reject;
				reader.onabort = reject;
				reader.onload = () => resolve(reader.result as string);
				reader.readAsDataURL(blob);
			});

			await Filesystem.writeFile({
				path: fileName,
				data: base64,
				directory: Directory.Documents,
			});

			Toast.show({ text: `ok ${fileName}` });
			Haptics.impact({ style: ImpactStyle.Light });
		} catch (e) {
			Toast.show({ text: `${e.toString()}` });
		}

Versions:

    "@capacitor/android": "^5.7.0",
    "@capacitor/app": "^5.0.7",
    "@capacitor/core": "^5.7.0",
    "@capacitor/filesystem": "^5.2.1",
    "@capacitor/haptics": "^5.0.7",
    "@capacitor/ios": "^5.7.0",
    "@capacitor/keyboard": "^5.0.8",
    "@capacitor/splash-screen": "^5.0.7",
    "@capacitor/status-bar": "^5.0.7",
    "@capacitor/toast": "^5.0.7",
1 Like

I have a similar implementation. I have the issue that PDF files are empty - the page number is correct, but there is no content. Image files are also invalid. Have you found any solution?

It works if I use Filesystem’s downloadFile method to download a file, but there are places where I cannot use that and I have the Blob from a “traditional” http request. I don’t know if it’s a problem with the http request on Android or the file writing / encoding / whatever.

May be you can update now.

npm install @capacitor-community/file-opener
npm install capacitor-blob-writer

From Stackoverflow: ionic framework - Capacitor download and open file from api - Stack Overflow
Capacitor Filsesystem: Filesystem Capacitor Plugin API | Capacitor Documentation
capacitor blob writer: GitHub - diachedelic/capacitor-blob-writer: Capacitor plugin to write binary data to the filesystem

Finally i did find out with Ionic Capacitor with only and pdfmake. Write it as base64 and remove the // encoding: Encoding.UTF8
It will automatically save as base64.

  async convertToTxt(textString: string)  {
    const docDef = {
      content: [
        { text: textString }
      ]
    };
    const fileName = `ImgToText_${Date.now()}.pdf`;
  
    if (Capacitor.isNativePlatform()) {
      pdfMake.createPdf(docDef).getBase64(async (data) => {
        try {
          const result = await Filesystem.writeFile({
            path: fileName,
            data: data, // Utilisation de la valeur Base64 obtenue
            directory: Directory.Documents,
            // encoding: Encoding.UTF8
          });
  
          if (result) {
            console.log('PDF Ă©crit avec succĂšs sur le systĂšme de fichiers:', result.uri);
            alert('PDF Ă©crit avec succĂšs sur le systĂšme de fichiers:\n' + result.uri);
            // Ajoutez ici le code pour ouvrir le fichier PDF si nécessaire
          } else {
            console.error('Erreur lors de l\'Ă©criture du fichier PDF sur le systĂšme de fichiers.');
            alert('Erreur lors de lécriture du fichier PDF sur le systÚme de fichiers.');
          }
        } catch (error) {
          console.error('Erreur lors de lécriture du fichier PDF:', error);
          alert('Erreur lors de lécriture du fichier PDF sur le systÚme de fichiers.');
        }
      });
    } else {
      // Télécharger le PDF dans le navigateur
      // const pdfBlob = await pdfMake.createPdf(docDef).getBlob();
      pdfMake.createPdf(docDef).download(fileName);
    }
  }