Read large files from the filesystem
See original GitHub issueMy app must be able to download images/video/audio for offline-perusal, on both iOS and Android. Pending #984, I have used cordova-plugin-file and cordova-promise-fs to store a downloaded blob to the filesystem, which is working nicely.
However, on both iOS and Android, whatever I try I cannot play a local video!
Using .toInternalURL()
<video src="cdvfile://localhost/persistent/data/user/0/com.example.app/cache/video.mp4"></video>
Throws error:
Mixed Content: The page at 'https://localhost:5174/' was loaded over HTTPS, but requested an insecure video 'cdvfile://localhost/persistent/data/user/0/com.example.app/cache/video.mp4'. This request has been blocked; the content must be served over HTTPS.
So cdvfile:
is considered an insecure protocol.
Using .toURL()
<video src="file:///data/user/0/com.example.app/files/files/data/user/0/com.example.app/cache/video.mp4"></video>
Throws error:
Not allowed to load local resource: file:///data/user/0/com.example.app/files/files/data/user/0/com.example.app/cache/video.mp4
I realise it’s a weird looking path, but that’s what I get from .toURL()
, and I don’t think that’s really the problem here.
Both the above examples behaved very similarly on my iOS simulator so I will not bother to post that error log here.
Failed approaches
Content-Security-Policy
I have tried tweaking the Content-Security-Policy
meta tag to include the cdvfile:
protocol, but according to this post you can only tighten security using that, not loosen it.
Potential solutions
Capacitor support for <access origin="cdvfile://*"/>
It appears Cordova may have a workaround for this issue, perhaps the functionality could be duplicated in capacitor.config.js
? However Cordova’s solution might be outdated.
Read as data URL
I can read the video as a Base64 string using fs.toDataURL()
and then supply a data:
URL to my <video>
element. This works fine on iOS and Android for small videos, but it will break for larger videos as browsers generally set a maximum size for strings (apparently ~256MB), and also loads the whole video into memory which is a big no-no.
Tweak Swift/Java
According to this, there is a way to allow mixed content on an Android WebView, perhaps there is also a way to get it working on iOS?
Use native video player
The VideoPlayer plugin can play local videos using an Android’s native player. I’d like to avoid this as I’m trying to keep compatibility with iOS and the browser.
Streams
If Capacitor’s FileSystem plugin could return a ReadableStream of the file, I’m sure a solution could be found. To avoid holding the entire file in memory at once, it could be piped into successive blobs, then stitched together into a larger blob and then turned into a playable URL using URL.createObjectURL()
. Chrome at least will write blobs to disk if memory pressure gets too high.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:3
- Comments:18 (12 by maintainers)
Top GitHub Comments
@saas786
Capacitor seems to provide as must storage space as the device can provide. But I could be wrong about that. I am using Capacitor v2.
To download a video to the filesystem, I use this plugin: https://github.com/diachedelic/capacitor-blob-writer/.
To play back a video from the filesystem, I do something like the following:
I submitted a PR to the file plugin which solves the mixed content problem on ios: https://github.com/apache/cordova-plugin-file/pull/296 The fixed version is available at: https://github.com/guylando/cordova-plugin-file If you load a remote site https://xxx.com on the webview then it allows to access local files using the url: https://xxx.com/cdvfile/bundle/www/cordova.js instead of cdvfile://localhost/bundle/www/cordova.js And by this solves the mixed content problems.