Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a blob data URL in WKWebView?

I have a WKWebView, but when I click on a link that has the following URL:

blob:https://www.mycase.com/2963c6c0-24c1-418f-a314-88f7a2dbc713

Nothing happens. Reading the documentation it describes:

The only way to read content from a Blob is to use a FileReader.

So I presume there is no way WKWebView is able to read the Blob itself by some method. As URLSession fails to download the content when you feed it the blob URL.

A solution I came up with myself is to read the blob in JavaScript itself.

var script = ""

script = script + "var xhr = new XMLHttpRequest();"
script = script + "xhr.open('GET', '\(navigationURL)', true);"
script = script + "xhr.responseType = 'blob';"
script = script + "xhr.onload = function(e) { if (this.status == 200) { var blob = this.response; var reader = new window.FileReader(); reader.readAsBinaryString(blob); reader.onloadend = function() { window.webkit.messageHandlers.readBlob.postMessage(reader.result); }}};"
script = script + "xhr.send();"

self.webView.evaluateJavaScript(script, completionHandler: nil);

Then add a script message handler to fetch the content.

let configuration = WKWebViewConfiguration()
configuration.userContentController.add(self, name: "readBlob")

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print(message.body)
}

It feels a bit cumbersome to do it like this, is there any other way?

like image 563
Mark Avatar asked Sep 06 '25 03:09

Mark


1 Answers

an alternative

Using fetch() instead of XMLHttpRequest, since fetch() API is more modern and might provide cleaner syntax for handling blobs.

const url = navigationURL;
fetch(url)
    .then(response => response.blob())
    .then(blob => {
        const reader = new FileReader();
        reader.onload = () => {
            window.webkit.messageHandlers.readBlob.postMessage(reader.result);
        };
        reader.readAsDataURL(blob);
    })
    .catch(e => console.error(e));

One more alternative is considerind encoding it in Base64, which might be more robust for handling in your native code.

Having said the above your solution is still quite good to be sincere.

like image 117
oetoni Avatar answered Sep 07 '25 19:09

oetoni