0

I have my WKWebView when I click on a file to download it. I have a popup writing:

No application configured to open the URL blob:https// ...

I tried to register a custom URL scheme blob to WKWebView, the application crash saying that this scheme is already supported by default.

However, when I click on the file, the delegate is not called:

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void)`

So I can't even know when a blob url is clicked to try to download the file by injecting JavaScript.

My application is for macOS.

enter image description here

qtmfld
  • 2,916
  • 2
  • 21
  • 36
Mickael Belhassen
  • 2,970
  • 1
  • 25
  • 46
  • Yes I’m trying to open a url blob. Look at the post I added a picture – Mickael Belhassen May 09 '20 at 19:35
  • if there is a solution in JavaScript I will accept a solution with. how can i listen for blob url to javascript and change the scheme? Do you have a code idea? I have already done research but without success – Mickael Belhassen May 09 '20 at 19:58
  • if nothing else works, you can try using a dataurl. but see if setting CSP works: `` – user120242 May 09 '20 at 20:03
  • This guy found a workaround that I guess is slightly better than having to convert to a dataurl: https://stackoverflow.com/questions/45065085/how-to-read-a-blob-data-url-in-wkwebview – user120242 May 09 '20 at 20:04
  • I do not have access to the site code. So I have to inject 'can you explain to me the code you advise me – Mickael Belhassen May 09 '20 at 20:06
  • I already saw what you tell me, put the listener does not work. that does not send any message to my webview – Mickael Belhassen May 09 '20 at 20:08
  • Just in case it might help you. Someone who has a full working program. Also used data uri, but I don't see why you the binary string method wouldn't work either: https://forums.developer.apple.com/thread/108394#333195 – user120242 May 10 '20 at 01:00
  • that's my real problem I can't intercept it in the delegate – Mickael Belhassen May 10 '20 at 05:34

1 Answers1

0

Note that this is a really roundabout hack. Scan all href and replace any blob urls detected with datauri. EDIT: updated to show it running

function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}
// not sure what elements you are going to intercept:
document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.getAttribute('href');
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.setAttribute('href',datauri));
   }
});

b=new Blob([new Int8Array([1,2,3,4,5,6,7,8,9,10]).buffer]);
test.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([31,32,33,34,35]).buffer]);
test1.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([51,52,53,54]).buffer]);
test2.href=URL.createObjectURL(b);



function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}

document.addEventListener('click', function(event) {
  event.preventDefault();
  if ( event.target.matches('a[href^="blob:"]') )
     (async el=>{
       const url = el.href;
       const blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
     })(event.target);
});

// not sure what elements you are going to intercept:
/*document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.href;
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
   }
});*/
<a id="test">test</a>
<a id="test1">test</a>
<a id="test2">test</a>

Example of data uri conversion on click:

b=new Blob([new Int8Array([1,2,3,4,5,6,7,8,9,10]).buffer]);
test.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([31,32,33,34,35]).buffer]);
test1.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([51,52,53,54]).buffer]);
test2.href=URL.createObjectURL(b);



function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}

document.addEventListener('click', function(event) {
  if ( event.target.matches('a[href^="blob:"]') ) {
     event.preventDefault();
     (async el=>{
       const url = el.href;
       const blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => window.open(el.href=datauri,el.target||'_self'));
     })(event.target);
   }
});

// not sure what elements you are going to intercept:
/*document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.href;
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
   }
});*/
<a id="test">test</a>
<a id="test1">test</a>
<a id="test2">test</a>
user120242
  • 14,918
  • 3
  • 38
  • 52
  • what if i don't want to scan for blob links, but listen as soon as a blob link is clicked? Because in a webapp the link is not always on the main page but after clicking on a button – Mickael Belhassen May 09 '20 at 20:18
  • use addEventListener instead. The async callback might make it awkward. Just make sure you preventDefault – user120242 May 09 '20 at 20:23
  • to make an addEventListener, the element must exist when the page loads? Or add a listener to the window? Can you show me an example – Mickael Belhassen May 09 '20 at 20:27
  • right, you'd have to have it execute after the DOM is ready. I'm not sure if injecting it into the WebView will cause any differences. It most likely shouldn't. Just remember that this is basically doing a base64 conversion after each click. Probably not a good idea with big files. If that SO link can work, it will probably be better than this. – user120242 May 09 '20 at 20:29
  • Thanks for your precious help – Mickael Belhassen May 09 '20 at 20:40
  • np. Let me (us) know if you find a better solution in the future. – user120242 May 09 '20 at 20:43