26

I know there's a lot of questions already existing on SO related to this kind of problem, for instance:

This question is very specific to Safari on iOS 8.1.3 (Mobile, iPad 2+). We have an offline AngularJS web app using Application Cache and IndexedDB to store data. One kind of data is PDF documents that can be relatively large: about 25 megabytes max. We are storing these files in IndexedDB and when the user wants to download it, we have this file in-memory within the browser with JavaScript.

The problem is really when the user wants to save it. Safari Mobile crashes maybe from a size limitation of Data URI or something else.

this.save = function (file) {
    var mediaType = "application/pdf";

    var link = document.createElement("a");
    var blob = new Blob([this.fromBase64ToBinary(file.content)], { type: mediaType });

    var blobUrl = URL.createObjectURL(blob);
    document.body.appendChild(link);
    link.download = file.name;
    link.href = blobUrl;
    link.click();
    document.body.removeChild(link);
};

In a service, we have a function save(file) where file is an object containing two properties:

  1. name: the filename;
  2. content: data of the file, which is base 64 encoded, then we transform it to binary.

The atob() function can be the cause? When I do a step-by-step debugging on the iPad running this code, it crashes right there (ie: line with var byteCharacters = atob(b64Data);).

this.fromBase64ToBinary = function (base64) {
    var byteCharacters = atob(base64);
    var byteNumbers = new Array(byteCharacters.length);
    for (var i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
    }

    return new Uint8Array(byteNumbers);
};
Community
  • 1
  • 1
sgy
  • 2,922
  • 2
  • 35
  • 42
  • 4
    Have a look at [this question](http://stackoverflow.com/questions/37277051/what-alternative-for-atob-on-ios) and [the answer](http://stackoverflow.com/a/37277200/4545506). Because `atob` in ios crashes when a space character exists. – ykaragol May 20 '16 at 08:20
  • Why you need to use base64? I'm asking because when you use, the file becomes 37% bigger. It will be approximately 37% larger: Very roughly, the final size of Base64-encoded binary data is equal to 1.37 times the original data size Source: http://en.wikipedia.org/wiki/Base64 – Marco Jun 22 '18 at 17:54
  • I have one question, does it break for all file sizes or specific file sizes? – VariableVasasMT Apr 16 '19 at 18:39
  • as per comment by @ykaragol, would a base64 encoded string have a space in it? https://stackoverflow.com/questions/3092019/can-a-base64-encoded-string-contain-whitespace – VariableVasasMT Apr 16 '19 at 18:40
  • @Marco the answer to your question is in the comment by ykaragol – VariableVasasMT Apr 16 '19 at 18:52

1 Answers1

1

I dealt with a similar issue. The way I solved it was this:

// Detects if Safari 9 or less
var isSafariNineOrLess = navigator.vendor && navigator.vendor.indexOf('Apple') 
> -1 &&
navigator.userAgent &&
navigator.userAgent.indexOf('CriOS') === -1 &&
navigator.userAgent.indexOf('FxiOS') === -1 &&
window.ApplePaySession === undefined;

...

if(!isSafariNineOrLess) {
    save(file);
}
else {
   var myLink = document.getElementById('myLink');
       if(myLink) {
          myLink.removeAttribute('href');
          myLink.setAttribute('href', 'http://example.com/download.pdf.zip');
        }
 }

Then when people click on the link they can download a zipped file that contains the PDF. You look like you are using https://github.com/eligrey/FileSaver.js, or something similar, and that absolutely does not work with Safari 9 and below.

Take a look at https://visualstudio.microsoft.com/thank-you-downloading-visual-studio-mac/?sku=communitymac&rel=16# in Safari 9 or below for the behavior I'm talking about, where the a tag href is changed to a URL to download a file.

Let me know if this works for you!