Я знаю, что существует много вопросов, уже существующих на SO, связанных с этой проблемой, например:
- Создайте файл в памяти для загрузки пользователем, а не через сервер
- Использование HTML5/Javascript для создания и сохранения файла
- Ограничения на размер URL-адреса протокола передачи данных
- Сохранить файл Javascript с именем файла
- Создание Blob из строки base64 в JavaScript
- Не удалось выполнить 'atob' в 'Window'
Этот вопрос очень специфичен для Safari на iOS 8.1.3 (Mobile, iPad 2+). У нас есть автономное веб-приложение AngularJS, использующее Application Cache и IndexedDB для хранения данных. Один вид данных - это документы PDF, которые могут быть относительно большими: максимум 25 мегабайт. Мы сохраняем эти файлы в IndexedDB, и когда пользователь хочет его загрузить, у нас есть этот файл в памяти в браузере с JavaScript.
Проблема в том, когда пользователь хочет ее сохранить. Ошибка Safari Mobile может быть связана с ограничением размера URI данных или чем-то еще.
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);
};
В службе у нас есть функция save(file)
, где file
- объект, содержащий два свойства:
-
name
: имя файла; -
content
: данные файла, который кодируется базой 64, затем преобразуем его в двоичный.
Функция atob()
может быть причиной? Когда я делаю пошаговую отладку на iPad, запускающем этот код, он падает прямо там (то есть: строка с 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);
};