23

I have a blob created with a base64, and I need to make this data downloadable as a pdf.

I created this snippet:

    var blob = new Blob([byte]);
    var link = document.createElement('a');

    link.href = window.URL.createObjectURL(blob);
    link.target = '_blank';
    var fileName = name + '.pdf';
    link.download = fileName;
    link.click();

It works on all the browsers, except safari mobile on iOS.

The file gets actually downloaded, but its name is "unknown", then it can't be open since the extension gets lost.

The problem is that the download attribute lacks support on this browser and IE.

There are a lot of workarounds for IE, but I didn't find any for Safari/iOS.

Do you know how can I download a blob got from a base64 (no XHR involved) in this browser?

Thank you

  • 1
    I am not sure whether your issue is the one described a https://github.com/keeweb/keeweb/issues/130 Another suggestion: Back in the days, when [CGI and perl](https://www.perl.com/article/perl-and-cgi/) was still a thing, I solved a similar issue by adding various different header lines within the [http response header](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields). You might have to use a lower-level JS library for that. Also, you need to see which headers are really interpreted by Safari, probably something with `content-disposition`. – B--rian Jul 22 '19 at 22:08
  • 5
    The question hadn't received enough attention, thank you @GerardoFurtado for the bounty. After a week, I'd confidently say that does not exist any specific workaround for this browser, and also the weirdest and most esoteric solutions, won't provide any satisfying result. About my specific case, I explained the problem to the marketing department, and we opted to view the file in a new tab. In other words, the adopted solution, in case we match the safari/IOS browser, is the following: `window.open('data:application/pdf;base64,'+escape(base64), '_blank');` – Christian Vincenzo Traina Jul 24 '19 at 08:34

4 Answers4

13

I need to make this data downloadable as a pdf (...) in safari iOS

SHORT ANSWER: you can't. Due this bug is impossible to download the file on safari iOS


The alternative is to open the file on the browser with the proper mime type, so it can show its content (and the user can then manually download it if needed).

Make sure to pass mime type when creating the Blob. reference

var blob = new Blob([byte], {type: 'application/pdf'});

Lastly, I'd strongly suggest you to use FileSaver.js which that can handle most of the corner cases/multiple browser support for save (or in this case, open) a file in javascript.

Diogo Sgrillo
  • 2,601
  • 1
  • 18
  • 28
  • FileSaver is not an option. From the docs: `Due to restrictions in iOS saveAs opens in a new window instead of downloading`. – Gerardo Furtado Jul 22 '19 at 22:37
  • 1
    @GerardoFurtado, it's precisely my point: at the moment, it's impossible to download the file on safari iOS because of a bug. Once the bug is fixed, likely FileSaver.js will be able to handle this issue accordingly. For the moment, the best thing one can do is open the file in a new window (which the user can manually download) – Diogo Sgrillo Jul 23 '19 at 10:04
  • In that case, your answer (and all others, by the way) should be just a comment. – Gerardo Furtado Jul 23 '19 at 10:07
  • @GerardoFurtado I've updated the answer again to make it more clear. Not sure why you think it should be a comment, though. According my interpretation of https://meta.stackoverflow.com/questions/366515/when-should-i-answer-and-when-should-i-comment, it is a fine answer. – Diogo Sgrillo Jul 23 '19 at 10:45
  • @DiogoSgrillo the bug you mentioned is marked Fixed Resolved in iOS 13. Is this still not possible? – Lord Zsolt Sep 18 '20 at 11:04
  • Some news here: it should be fixed in Chrome 99 (planned for March 1st, 2021). I made a thread explaining the situation (https://twitter.com/meduzen/status/1484101126844829698), but here’s the essence… 1) There’s a fix (https://chromium.googlesource.com/chromium/src/+/652a83baf169d5bc57b6f277ce301a0eb0386ddd%5E%21/). 2) The commit is in the Chrome 99 list of commits (https://chromium.googlesource.com/chromium/src/+log/refs/tags/99.0.4840.3/ios/web/navigation/crw_wk_navigation_handler.mm) 3) No temporary fix: host the file or remove the `download` and ask user to click. – meduz' Jan 20 '22 at 09:58
2

As per the below link:-

https://caniuse.com/#feat=download

Safari 13 Beta 3 is released so you can check on the same, whether its working or not?

You can download a blob got from a base64 by using a atob function.

The atob function will decode a base64-encoded string into a new string with a character for each byte of the binary data.

You can save blob locally via FileSaver.js .

You can also check here that would be helpful:- How to open Blob URL on Chrome iOS

Parveen yadav
  • 2,252
  • 1
  • 21
  • 35
2

This is something I have tried in my project and it is working for me.

import "./styles.css";

var pdfData =
  "JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog" +
  "IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv" +
  "TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K" +
  "Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg" +
  "L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+" +
  "PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u" +
  "dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq" +
  "Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU" +
  "CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu" +
  "ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g" +
  "CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw" +
  "MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v" +
  "dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G";

let download = () => {
  if (pdfData) {
    var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
    var isChrome =
      navigator.userAgent.toLowerCase().indexOf("CriOS") > -1 ||
      navigator.vendor.toLowerCase().indexOf("google") > -1;
    var iOSVersion = [];
    if (iOS) {
      iOSVersion = navigator.userAgent
        .match(/OS [\d_]+/i)[0]
        .substr(3)
        .split("_")
        .map((n) => parseInt(n));
    }
    var attachmentData = pdfData;
    var attachmentName = "Test.pdf";
    var contentType = "application/pdf";

var binary = atob(attachmentData.replace(/\s/g, ""));
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);
for (var i = 0; i < len; i++) {
  view[i] = binary.charCodeAt(i);
}
var linkElement = document.createElement("a");
try {
  var hrefUrl = "";
  var blob = "";
  if (iOS && !isChrome && iOSVersion[0] <= 12) {
    blob = "data:application/pdf;base64," + pdfData;
    hrefUrl = blob;
  } else {
    if (iOS && !isChrome) {
      contentType = "application/octet-stream";
    }
    blob = new Blob([view], { type: contentType });
    hrefUrl = window.URL.createObjectURL(blob);
  }
  linkElement.setAttribute("href", hrefUrl);
  linkElement.setAttribute("target", "_blank");
  if ((iOS && (iOSVersion[0] > 12 || isChrome)) || !iOS) {
    linkElement.setAttribute("download", attachmentName);
  }
  var clickEvent = new MouseEvent("click", {
    view: window,
    bubbles: true,
    cancelable: false
  });
  linkElement.dispatchEvent(clickEvent);


   } catch (ex) {}
  }
};

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={download}>Download</button>
    </div>
  );
}

enter image description here

RRR
  • 3,509
  • 4
  • 29
  • 38
-1

The "target" attribute in Safari seems to override the "download" attribute. Currently, as to my knowledge, there is no way to solve this. So I think you have to wait for the next Safari version (13) which will be out in a few months.

Dat Le
  • 308
  • 2
  • 7
  • This answer is plain wrong. There is no `download` attribute for anchor elements in mobile Safari, if you try it's simply `undefined`. Therefore, there is nothing to be overridden. – Gerardo Furtado Jul 23 '19 at 01:20