Sharesheet from WebView does not recognize PDF

There is a way (didn’t know it myself):

At first, you have to get the blob that contains the PDF from the blob URL (Source):

let blob = await fetch(url).then(r => r.blob());

Then, you have to convert this blob into a data URL, like @flyingeek has linked (Source):

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

And all that has to be evaluated in the WebView. So as a complete example:

This code doesn’t work. Look below for a working version

let script = `
(async function() {
  let url = window.location.href; // or any other method to get the url

  let blob = await fetch(url).then(r => r.blob());

  blobToDataURL(blob, completion); // pass the result directly to the completion function
})();

function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}
`;
// wv is the WebView instance containing your PDF
let pdf = await wv.evaluateJavaScript(script, true);

I hope, it works. I haven’t tested it, nor do I know, if you can execute javascript in a WebView that displays a PDF…

Edit:

If this works, then pdf contains the data URL of the PDF. To save it as a file:

let pdf = await wv.evaluateJavaScript(script);

pdf = pdf.replace(/^data:[^,]+,/, "");
log(pdf)

let data = Data.fromBase64String(pdf);
let fm = FileManager.iCloud();
// change "my.pdf" to the name you want
let path = fm.joinPath(fm.documentsDirectory(), "my.pdf");
fm.write(path, data);

This code should work, at least it did for me.

Another edit

I’ve now had the chance to test this code thanks to this thread:

It looks like you can run javascript in the blob page, but Scriptable seems to struggle to register its global variables (log and completion). Because of this the code fails and never returns anything.

A workaround is to redirect the WebView to the data URL and then extract it via javascript:

// wait for the page to display the pdf as blob
await wv.waitForLoad();

let script = `
let url = window.location.href;

let blob = fetch(url)
  .then(r => r.blob())
  .then((blob) => {
    blobToDataURL(blob);
  });

function blobToDataURL(blob) {
  var a = new FileReader();
  a.onload = function(e) {
    // instead of trying to return it, load it
    location.href = e.target.result;
  };
  a.readAsDataURL(blob);
}
`;
// since we don't return anything from the script, we don't need to run it async. because scriptable struggles with registering the completion function, it won't even work when running it async
await wv.evaluateJavaScript(script);

// wait until the new url has loaded
await wv.waitForLoad();

// get the url
let pdf = await wv.evaluateJavaScript("location.href");

To now save the PDF, look at my previous edit above.