jimmywarting / StreamSaver.js

StreamSaver writes stream to the filesystem directly asynchronous
https://jimmywarting.github.io/StreamSaver.js/example.html
MIT License
3.97k stars 413 forks source link

How to use StreamSaver.js in Android webview like Chrome #236

Open Sonumohammad opened 3 years ago

Sonumohammad commented 3 years ago

Chrome (Android app) is handling downloads from StreamSaver.js How can I achieve this with Android's webview? https://stackoverflow.com/questions/67708173/how-to-download-stream-streamsaver-js-files-in-android-webview

jimmywarting commented 3 years ago

I'm not sure...

maybe this can help. https://stackoverflow.com/questions/10069050/download-file-inside-webview

@warting do you have any suggestion?

Sonumohammad commented 3 years ago

These solutions are for normal file downloads with URLs. In these solutions, download info from Webview will be passed to DownloadManager only once. But in the StreamSaver.js case, the download simply starts and fails because DownloadManager doesn't communicate with Webview in real-time.

do you have any solution?

jimmywarting commented 3 years ago

ok, i might have found something when i explained to my brother how streamsaver works

the url that is generated from streamsaver is a uniq "one-time" download link and totally client side generated by a service worker... You can't simply take the url that is generated and pass it to another browser (or another download mananger) to download it cuz it's generated by a service worker (in the browser). opening this url again will result in 404

I guess what you actually have to do is to download/intercept the content that flows in as a readable stream. so this will probably not work...

        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
            // Downloading with DownloadManager is not working.
            // A notification says, download failed.
        }

i found something that might be of interest doe and it's probably something that i would have used... it's called shouldOverrideUrlLoading and conn.getInputStream

https://stackoverflow.com/a/38732113/1008999

from my understanding this should give you the content as a InputStream which you can use to write to any destination.

gwdp commented 2 years ago

I'm working to solve an issue where it seems that streamsaver does not work on the following Chrome mobile environments:

Few details on the investigation:

All being said, I might need to improve the useBlobFallback detection for those environments (unsure if we can handle without blobs) and find a way to download blobs using onDownloadStart; However, making it work on Chrome App is also important and I have no clues on doing so ( for now 🤓 )

Sonumohammad commented 2 years ago

I am JavascriptInterface instead of StreamSaver Send Bytes from Javascript to Java, Write bytes to file stream in Java

  1. Set JavascriptInterface with Webview 1.1 Create a class MyJSInterface 1.1 Create method(s) in MyJSInterface with @JavascriptInterface annotation so you can call the methods from Javascript, you cannot send byte arrays from Javascript to android For that we convert byte array to string before sending 1.2 create method, newBytes(String convertedString) in MyJSInterface 1.2 Add MyJSInterface to Webview webview.addJavascriptInterface(new MyJSInterface(this), "Android")

  2. Javascript 2.1 Convert bytes to string 2.2 Send to Java environment with MyJSInterface Android.newBytes(convertedString)

  3. Java 3.1 Handle newBytes(convertedString) Convert string to bytes 3.2 Write the bytes to FileStream

Use webworker(JS) to asynchronously pass byte stream to Java

Reference: https://stackoverflow.com/a/45506857/14421932

gwdp commented 2 years ago

Hi @Sonumohammad, thanks for the reply..

My goal is more specifically on making streamsaver work with those cases instead of replacing its usage.

Further testing it, I was able to make it work with Android WebView using JavascriptInterface + ajax injection + java callback on the blob: schema, however, attempting to make it work without the blobfallback is giving me nightmares. Will stick on the attempt for a while, if no success will probably need to patch streamsaver to fallback to blob on those cases (which is not doing right not 2.0.6.

If I understood the depth of this issue correctly, streamsaver is currently not working on any Android mobile engine, so needs attention for sure. Any thoughts are much appreciated :)