I know there's a lot of questions already existing on SO related to this kind of problem, for instance:
- Create a file in memory for user to download, not through server
- Using HTML5/Javascript to generate and save a file
- Data protocol URL size limitations
- Save file Javascript with file name
- Creating a Blob from a base64 string in JavaScript
- Failed to execute 'atob' on 'Window'
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:
name
: the filename;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);
};