Guardar Archivos en Android con Capacitor

¿Por qué el FileSystem es tan extraño?

Nos ocurrió algo curioso al desarrollar una de las tantas Apps en producción, lo que con Apache Cordova era realmente sencillo (guardar un archivo en X directorio) con Capacitor se volvió un desafío. La forma más interesante y sencilla que hay es las siguiente:

const result = await Filesystem.writeFile({
      path: 'holamundo.txt',
      data: 'Hola Mundo',
      directory: Directory.Documents,
      encoding: Encoding.UTF8,
});

Esto funciona, creando una carpeta Documents en el directorio raiz, siendo accesible fácilmente. No obstante puede producir problemas al abrir el archivo a posterior, debido a que aun no se trata de una plataforma estable el tema de los directorios. Tampoco existe un "Opener" como si pasaba con Apache Cordova. Revisando un poco la forma en la que opera nos dimos cuenta de que la mejor opción es "trayendo a la vida" ese viejo plugin de Cordova. Primero instalamos los paquetes de NPM:

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

Esto nos va a agregar el file-opener2 (los veteranos lo recordarán) junto con la "estabilización" hecha por ionic para Capacitor. Sin embargo, en Android, el plugin utiliza un paquete llamado android4 que ya no tiene soporte, por lo tanto vamos a modernizarlo a androidx:

npm install jetifier
npx jetify
npx cap sync android

Ahora con todo esto, en nuestro componente de Angular vamos a importarnos las dependencias:

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

Y finalmente vamos a armar el sistema que guarde y abre el archivo en el mismo proceso:

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('Archivo abierto'))
            .catch(e => console.log('Error al abrir achivo', e));
        console.log('Archivo escrito', result.uri);
    } catch (e) {
        console.error('Imposible escribir el archivo', e);
    }
}

Varias consideraciones al respecto de este código. Para empezar es cortesía de Georg Hoeller en su blog. Otro punto importante, utiliza el directorio Data para que el archivo sea público, pero no siempre dicho directorio funciona (chequear eso). Se basa en una generación de archivos en blob inicialmente (de hecho la variable data debe ser un blob) para luego codificarlo a base64; por lo tanto tener en cuenta eso, si ya estan generando el archivo en base64 lo pueden enviar directamente como data sin hacer la conversión. Finalmente, es recomendable tenerlo en un service o función a parte para llevarlo de la forma en que uno quiera. Supongo que está especialmente pensado para PDF, ya que con archivos más simples como CVS o TXT da problemas. Para el caso de archivos CSV, lo ideal será primero convertirlos a blob:

const blob = new Blob([csvContent], { type: "text/csv" });

Ya con eso generado el código antes presentado lo tomará correctamente.

Entradas Relacionadas

Guardar Archivos en Android con Capacitor
Ignacio Buioli 16 de febrero de 2022
2 min. de lectura
Compartir
Categorías
Archivar