capacitor
capacitor copied to clipboard
bug: convertFileSrc Does Not Work in Web
Bug Report
Capacitor Version
Latest Dependencies:
@capacitor/cli: 2.4.0
@capacitor/core: 2.4.0
@capacitor/android: 2.4.0
@capacitor/electron: 2.4.0
@capacitor/ios: 2.4.0
Installed Dependencies:
@capacitor/android not installed
@capacitor/ios not installed
@capacitor/cli 2.4.0
@capacitor/core 2.4.0
@capacitor/electron not installed
Platform(s)
Web.
Current Behavior
I followed the sample in the documentation. However, the converted path does not work on the browser showing GET http://localhost:8100/DATA/demo 404 (Not Found).
Expected Behavior
The image should be loaded with the provided path.
Code Reproduction
The minimal sample Ionic project can be found in this repository.
A tiny image is hard-coded as base64 string in the data field when writing the file with Capacitor Filesystem API.
const writeResult = await Filesystem.writeFile({
data: 'iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAA9aVRYdENyZWF0aW9uIFRpbWUAAAAAADIwMjDlubTlhavmnIgzMeaXpSAo6YCx5LiAKSAyM+aZgjI35YiGMjTnp5IACi9UAAAASElEQVQImWOUk5P7z4AFsEAoSQa/kGYGu2ezGbazuzP4K8jBJBgYGBjYGETVwxiszi9gaDp0A1mCgYHh7U6G6RcuM7xhYGAAAEFTDx/VUsAUAAAAAElFTkSuQmCC',
directory: FilesystemDirectory.Data,
path: 'demo',
recursive: true
});
this.src = Capacitor.convertFileSrc(writeResult.uri);
const readResult = await Filesystem.readFile({
directory: FilesystemDirectory.Data,
path: 'demo'
});
this.base64Src = `data:image/png;base64,${readResult.data}`;
The template shows two identical images with different approach: by path and by base64 string.
<img [src]="src" />
<img [src]="base64Src" />
The first image throws a 404 error.
Other Technical Details
npm --version output: 6.14.8
node --version output: v10.16.0
Other dependencies can be found in the sample project.
This example may not translate well to web. The Capacitor FS plugin uses IndexedDB for the web implementation, so there aren't any actual file paths to convert.
@dwieeb The documentation needs to be updated to reflect this limitation. Also, the implementation should throw an error instead of return the same value.
https://github.com/ionic-team/capacitor/blob/d7bf775dfb3857e5fc0edb2b24cbe32f56b821b0/core/src/web-runtime.ts#L64-L66
It works if you use DOMSanitizer, like this:
this.sanitizer.bypassSecurityTrustUrl(Capacitor.convertFileSrc(URI))
Sanitizer should be injected in constructor.
@Gorshtak Thanks for the suggestion. However, it does not work after I apply DOMSanitizer to the URL.
this.sanitizedSrc = this.sanitizer.bypassSecurityTrustUrl(Capacitor.convertFileSrc(writeResult.uri));
You can find the sample project here.
Oh sorry, i just noticed that you said it doesn't work on web. Well FileSystem is a plugin that provides manipulation of files on native devices. I don't see why would you use it on web.
@Gorshtak I try to build apps with Capacitor on native devices. However, it is still convenient for me to fast prototype the look and feel on the browser with ionic serve before applying to the native environment. Furthermore, the official documentation says the Filesystem plugin supports Android, iOS and PWA, which is misleading as the WriteResult.uri is not usable on PWA. This should be at least documented.
Well if you go a little bit deeper into the documentation inside FIleSystem you can see that they don't mention web anywhere.
For example look at this:
There is no explanation what it does on WEB.
But i completely agree with you that it should be documented that FileSystem does not support WEB
@Gorshtak The document has the icon for PWA support:

I had similar problem, on android 10 only
so basically for angular:
import { WebView } from '@ionic-native/ionic-webview/ngx';
constructor(private webView: WebView) {}
...
this.webView.convertFileSrc(path)
or you can also follow official ionic way https://forum.ionicframework.com/t/how-to-use-capacitors-convertfilesrc-instead-of-cordovas-convertfilesrc/167283
you dont need to do "http://localhost/" + relative path(i saw on different forums this way of solving), the problem is that if you have live-reloading enabled, convertFileSrc will convert your path to "http://192.168..../" (external adress). If You disable live-reloading, and remove "server": "{...}" from your capacitor.config.json your convertFileSrc will convert path to "http://localhost/..."
but still, all works fine on 7, 8, 9, 11 android. 10 still throws 404(OK) and if i try to send to backend images that was parsed with this error i will get error in console: EACCESS (Permission Denied)
Solved this by adding ' android:requestLegacyExternalStorage="true" ' in AndroidManifest.xml in tag
If you deploy into a web app this function isn't going to work.
As they said about convertfilesrc :
"Convert a device filepath into a Web View-friendly path." (https://capacitorjs.com/docs/basics/utilities#convertfilesrc).
As I understood, on a web context (ionic serve) the file isn't "exist", it is kept in memory via IndexedDB even if you save it via FileSystem plugin (who wrap your file into indexexDB).
Your second approach <img [src]="base64Src" /> is the right one. The base64 come from the IndexedDB database created by FileSystem plugin.
So, depend on the platform your app is (mobile, web, electron, etc..) you have to readfile() differently.
Hope this can help you.
Is there any workaround?
@goforu, let's say you have a function getAttachmentSrc(path: string) that takes a path and returns a src (usable as src attribute):
async function getAttachmentSrc(path: string): Promise<string> {
const { uri } = await Filesystem.getUri({
directory: Directory.Documents,
path,
});
return Capacitor.convertFileSrc(uri);
}
Workaround would be returning a data url on web:
async function getAttachmentSrc(path: string): Promise<string> {
if (Capacitor.isNativePlatform()) {
const { uri } = await Filesystem.getUri({
directory: Directory.Documents,
path,
});
return Capacitor.convertFileSrc(uri);
} else {
// work around for web
const { data } = await Filesystem.readFile({
directory: Directory.Documents,
path,
});
return URL.createObjectURL(data as Blob);
}
}
Hope this helps.