Hello everyone and thanks for taking time to read and answer.
DESCRIPTION
I am using Ionic 6 with Angular 14 and capacitor. I need to copy the content of an ZIP file uploaded by the user (it contains .sqlite files), and store it inside the Documents folder. For that, I'm using JSZip library.
public async unzipFolder(file: File): Promise<string[]> {
const zip: JSZip = await JSZip.loadAsync(file);
const promises: Promise<string>[] = [];
zip.forEach((relativePath: string, zipFile: JSZipObject) =>
promises.push(this.unzipFile(zipFile));
);
return await Promise.all(promises);
}
public async unzipFile(compressedFile: JSZipObject): Promise<string> {
return await compressedFile.async('string').then((data: string) => {
this.fileOpsService.write(compressedFile.name, data)
});
}
Everything works fine here. Problems comes when I try to store it in Documents folder using Filesystem plugin (capacitor).
public async write(
path: string,
data: string,
directory: Directory = Directory.Documents
): Promise<WriteFileResult> {
return await Filesystem.writeFile({
path: path,
directory: directory,
data: data,
recursive: false,
});
}
XCode's terminal throws this error:
{"errorMessage":"Unable to save file"}
I tried File plugin (awasome-cordova-file) but it does not work.
public async write(
path: string,
data: ArrayBuffer,
directory: Directory = Directory.Documents
): Promise<any> {
return await File.writeFile(path, '', data, {replace: true})
}
It throws the next error:
[DocumentManager] Failed to associate thumbnails for picked URL file:///private/var/mobile/Containers/Shared/AppGroup/XXX/File Provider Storage/TEST_BATCH2.zip with the Inbox copy file:///private/var/mobile/Containers/Data/Application/XXX/tmp/io.ionic.starter.ivan-Inbox/TEST_BATCH2.zip: Error Domain=QLThumbnailErrorDomain Code=102 "(null)" UserInfo={NSUnderlyingError=0x282532cd0 {Error Domain=GSLibraryErrorDomain Code=3 "Generation not found" UserInfo={NSDescription=Generation not found}}}
TESTED SOLUTIONS
- I tried to read the ZIP files as ArrayBuffer or Blob, but the Filesystem plugin can only use string data, so it didn't work.
- I also try to change the encoding value of Filesystem to UTF-8, UTF-16 and ASCII but it didn't work. The default value is Base64 encoding.
- I try to use the cordoba File plugin. In previous app versions this was working fine, so I try it (when the app used cordoba instead capacitor). Didn't work.
THEORIES
- I'm not sure about what is happening here, but seems than could be something related with encoding. Filesystem is not designed 4 copy .sqlite files I suppose.
- Maybe something related with relative paths, but I don't think so.
- Some Apple sh*t, u know...
Notes
- I just need it to work in iOS and Electron platforms. Browser could be a plus, but is not required.
- I know that an API/REST approach could be better, but it's not posible for this app. We need to store the data localy.
CodePudding user response:
Ok. After a few days, I finally found a solution. Here is it, if it can help anyone...
I changed the way of read from ZIP file by replacing 'string' with 'blob' as you can see in the following snippet:
public async unzipFile(compressedFile: JSZipObject): Promise<void> {
return await compressedFile.async('blob').then(async (data: Blob) => {
const filename: string = compressedFile.name
.replace('.sqlite', 'SQLite.db');
const base64 = await this.convertBlobToBase64(data);
this.fileOpsService.write(filename, base64);
});
}
I create a convertBlobToBase64 helper function that looks like this:
private convertBlobToBase64 = (blob: Blob) => new Promise((resolve, reject) => {
const reader: FileReader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result);
}
reader.readAsDataURL(blob);
})
And it works! Note that I replaced the filename because I need it in that format to read it with another plugin =)