[Angular | Capacitor] How to save and/or open file

The Capacitor Framework helps you in a lot of situations and makes it easy to build an app out of a finished angular website.
But not everything is working out of the box. In this short tutorial, I will show you how to save and open files in a capacitor app.

Version Information

Capacitor: 3.2
Angular: 11.1

Capacitor Utils

To prevent code duplications I created a 'capacitorUtils.ts' file in my angular workspace and created the class 'CapacitorUtils'. Place the file in a folder you can access from everywhere - I placed it in a shared folder.
Your file should look like the following:

import { Capacitor } from '@capacitor/core';

export class CapacitorUtils {
    static readonly isApp = Capacitor.getPlatform() !== 'web';
}

I added a static variable to check the platform we are running at. You may need this to differ if you should run the following code or the default browser download logic.

Plugins

For this tutorial you have to install 3 Plugins:

npm install @capacitor/filesystem
npm install cordova-plugin-file-opener2
npm install @ionic-native/file-opener

References:
https://capacitorjs.com/docs/apis/filesystem
https://ionicframework.com/docs/native/file-opener

With the filesystem plugin from capacitor, you can write data to the phone's file system.
With the ionic file opener, you can open the file with the default app for the specific mime type.

Don't forget to call capacitor to sync!

npx cap sync

Android

If you don't use android - skip this section :)

After the sync command I wasn't able tobuild the android solution.
It failed at the file "FileProvider" because the plugin is too old.
To fix this open the file and find the following line:

public class FileProvider extends android.support.v4.content.FileProvider {

Replace the whole line with this:

public class FileProvider extends androidx.core.content.FileProvider {

Edit 09.02.22
You can fix this problem with jetifier - just run the following (works with every old plugin which doesn't support androidx):

npm install jetifier
npx jetify
npx cap sync android

Save and Open Blob Data

Open your 'capacitorUtils.ts' file and add the following method in the CapacitorUtils class:

static async writeAndOpenFile(data: Blob, fileName: string) {
    var reader = new FileReader();
    reader.readAsDataURL(data);
    reader.onloadend = async function () {
        var base64data = reader.result;
        try {
            const result = await Filesystem.writeFile({
                path: fileName,
                data: <string>base64data,
                directory: Directory.Data,
                recursive: true
            });
            let fileOpener: FileOpener = new FileOpener();
            fileOpener.open(result.uri, data.type)
                .then(() => console.log('File is opened'))
                .catch(e => console.log('Error opening file', e));

            console.log('Wrote file', result.uri);
        } catch (e) {
            console.error('Unable to write file', e);
        }
    }
}

Don't forget to add all the imports for the source above:

import { FileOpener } from '@ionic-native/file-opener/ngx';
import { Filesystem, Directory } from '@capacitor/filesystem';

This code takes a blob object and writes it to the data directory from the phone. To open the file we created a new FileOpener and use the resulting path from 'writeFile'.
If everything works as intended we should have downloaded the file to our device and it should open automatically.

Now you can call this code from anywhere in your angular app.

if (CapacitorUtils.isApp)
    CapacitorUtils.writeAndOpenFile(result.data, filename);
else
    saveAs(result.data, filename);

Problems

Whenever I run into any kind of issue with this code I will add it here:

  1. Recently I had to download and open a .csv file and it failed. I had to set the mime-type manually to 'text/plain'.

I hope you enjoyed reading this short capacitor tutorial. Keep coding!