Capacitor Filesystem API

Using the Capacitor Filesystem API to Store Photos



·

When we take a photo on an iOS device, the resulting file is stored inside of a temporary folder called tmp. If we use the Camera API to retrieve a photo, the resulting URI will look like this:

file:///private/var/mobile/Containers/Data/Application/5C3AFB5A-8A33-4152-932D-32889401E966/tmp/photo-1.jpg

If we are interested in long-term storage then this isn’t the best solution. The way you approach this will depend on what it is your application is trying to achieve. You might want to send this photo to a server, or maybe you want to store the base64 data that is returned, in which case it isn’t going to matter if this temporary file gets deleted. However, for this example, we are going to rely on displaying a photo in an application by referencing the URI of the file on the device directly.

In this tutorial, we will be covering how to use Capacitor to retrieve a photo from the user’s camera or photo library, and then moving that photo into a permanent storage folder. I use the term “permanent” loosely, as of course data can always be deleted. If it is important that the photos in your application are never lost, you should investigate also storing them elsewhere (e.g.on a server). There is also the option to save a copy of any photos your users take to the user’s own photo library, so if the data ever is lost at least they will have their own copy of it.

In order to take a photo and move it to permanent storage, we will need to use both the Camera API and the Filesystem API that Capacitor provides. I’ve dicussed using the Camera API with Ionic before, but the Filesystem API will allow us to work directly with files on the device – we can create files, modify files, delete files, create directories, and more. One of the goals of Capacitor was to implement a Filesystem API that would be easier to use than the existing File API in Cordova.

1. Install Capacitor

In order to work with Capacitor, you will need to install the core package and the Capacitor CLI. As Capacitor is still in alpha, I would recommend following the instructions here to install Capacitor. Since it is in alpha, keep in mind that not everything is fully completed and documented, and there is potential to run into bugs/issues.

Although the example I am talking through was built to be used with an Ionic/Angular application, it doesn’t really have any bearing on the result. Neither Ionic or Angular are required to use Capacitor.

2. Import the Camera and Filesystem APIs

As I mentioned, we are going to need to use both the Camera and Filesystem APIs. The Camera API will allow us to retrieve a photo from the user, and the Filesystem API will allow us to move it into permanent storage.

To set these up, you will need to import the following:

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

and create a reference to the Camera and Filesystem:

const { Camera, Filesystem } = Plugins;

3. Take a Photo

In order to achieve the functionality we want, we mostly just use the Camera API as we usually would, with one important distinction:

    let options = {
      resultType: CameraResultType.Uri
    };

    Camera.getPhoto(options).then(

        (photo) => {
            console.log(photo);
        }, (err) => {
            console.log(err);

        }

    );

It is important that we supply the resultType option and use the CameraResultType.Uri value. If we supply this option, the result we receive will contain a path property that contains the path to the file on the device (in the temporary folder). We need this in order to copy it elsewhere.

4. Move the Photo to Permanent Storage

With a reference to the photo in the temporary folder, we can move it to another folder using the Filesystem API. Let’s take a look at how to do that, and then talk through it:

        Camera.getPhoto(options).then(

            (photo) => {

                Filesystem.readFile({
                    path: photo.path
                }).then((result) => {

                    let date = new Date(),
                    time = date.getTime(),
                    fileName = time + '.jpeg';

                    Filesystem.writeFile({
                        data: result.data,
                        path: fileName,
                        directory: FilesystemDirectory.Data
                    }).then((result) => {

                        Filesystem.getUri({
                            directory: FilesystemDirectory.Data,
                            path: fileName
                        }).then((result) => {
                            console.log(result);
                            let path = result.uri.replace('file://', '_capacitor_');
                        }, (err) => {
                            console.log(err);
                        });

                    }, (err) => {
                        console.log(err);
                    });

                }, (err) => {
                    console.log(err);
                });

            }, (err) => {
                console.log(err);
            }

        );

There are three stages here. First, we read the data from the file that was created by the Camera API. We then use that data to write a new file into the data directory. We use the current time to create a unique file name. Then we use getUri to return the URI of the file that we just created in the data directory. I suspect in future we will be able to grab that URI directly from the result of the writeFile method, but for now, this method does not return data about the file that was written.

If we take a look at the URI that is returned, it will look something like this:

file:///var/mobile/Containers/Data/Application/5C3AFB5A-8A33-4152-932D-32889401E966/Documents/1523843246419.jpeg

Notice that the photo is now in the Documents folder, rather than the tmp folder.

If we want to display this image in an Ionic application it won’t work, as we cannot display an image using an <img> tag that loads over the file:// protocol. However, Capacitor provides a way to access these files that is compatible with a web view. All we need to do is replace the file:// prefix with _capacitor_. In the future, there will likely be a way to do this with the API itself (the Camera API already returns this _capacitor_ link as the web path). For now, we can just manually modify the path string for the file that we moved to permanent storage with a string replace:

let path = result.uri.replace('file://', '_capacitor_');

which will result in the following URI:

_capacitor_/var/mobile/Containers/Data/Application/5C3AFB5A-8A33-4152-932D-32889401E966/Documents/1523843246419.jpeg

You could now safely display that inside of an <img> tag:

<img src="_capacitor_/var/mobile/Containers/Data/Application/5C3AFB5A-8A33-4152-932D-32889401E966/Documents/1523843246419.jpeg" />

Summary

We now have our photo stored outside of the tmp folder which is more likely to be wiped by the operating system at some point. Although we are specifically looking at moving a photo around the file system in this example, the Filesystem API is very powerful and can be used in a multitude of situations with different file types. To see the other types of file operations that this API can perform, you should take a look at the documentation.

What to watch next...