ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
11.83k stars 994 forks source link

bug: convertFileSrc Does Not Work in Web #3491

Open seanwu1105 opened 4 years ago

seanwu1105 commented 4 years ago

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.

imhoffd commented 4 years ago

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.

seanwu1105 commented 4 years ago

@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

Gorshtak commented 3 years ago

It works if you use DOMSanitizer, like this: this.sanitizer.bypassSecurityTrustUrl(Capacitor.convertFileSrc(URI)) Sanitizer should be injected in constructor.

seanwu1105 commented 3 years ago

@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.

Gorshtak commented 3 years ago

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.

seanwu1105 commented 3 years ago

@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.

Gorshtak commented 3 years ago

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:

Screenshot 2020-11-05 at 16 23 34

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

seanwu1105 commented 3 years ago

@Gorshtak The document has the icon for PWA support:

Screenshot from 2020-11-05 23-38-47

ghost commented 3 years ago

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

Jonathan-J8 commented 3 years ago

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.

goforu commented 1 month ago

Is there any workaround?