Problems saving in iOS Safari #12

Closed
gawry opened this Issue Jan 8, 2013 · 158 comments

Comments

Projects
None yet

gawry commented Jan 8, 2013

Edit by @eligrey: Please tell Apple how this bug is affecting you in https://bugs.webkit.org/show_bug.cgi?id=102914 if you want this fixed.

Edit by @jimmywarting
The safari bug #102914 has been marked as fixed now

according to the commit position, download attribute is fixed in WebKit v602.1.27.
The latest beta build (Safari Technology Preview) is based on WebKit v602.1.25, and of course doesn't contain this patch, so there's no simple way to test.

In the meantime, if you want to support Safari 7, you'll probably want to use Downloadify (uses Flash, not HTML5).


Issues we have had with Safari

  • Blob is not supported

    This has been solved with Blob.js using BlobBuilder as fallback and then base64 data uri if that are not supported either
  • URL.createObjectUrl
    Has been covered by both FileSaver.js and blob.js
    Blob.js overrule createObjectUrl with it's own base64 url constructor only if it's a "fake blob" (i.e not a File or Blob representation) it will use window.URL, fallback to window.webkitURL or use it's own base64 function to create those "fake blobs" data-uri
  • The "can't open blob url" issue (partly supported) - screenshot

            The page you opened redirected you to a page that isn't supported by safari
Safari can't open the page becuse Safari can't be redirected to address that begin with "blob:".

  • This is mostly cased by unsupported mime type, Safari do support opening blob url, but only if it's a mimetype that safari can understand like simple plain/text or a common image like image/png.
    • This will result in a new tab from which the user can just hit +S to save it
  • ATM FileSaver.js looks at the mimetype to see if it is application/octet-stream (wish is commonly used to force saving files from the server)
    If it's then it read the blob as base64 using FileReader to open a data:attachment/file" + base64 url in order to save it.
    • It's not possible to create a blob with attachment/file type directly and open it, then you will get errors like this: Failed to load resource: Frame load interrupted it has to be base64 for some reason...
    • the resulting filename will be "unknown" when doing this
  • The blank page error partial supported - (formuly known as "can't open blob url", see above)

    This can easily be reproduced by doing:
window.onclick = function(){
    var blob = new Blob(["Hi"], {type: 'application/octet-stream'});
    var url = URL.createObjectURL(url);
    window.open(url);
}

If you replace window.open with location.href = you will get the Failed to load resource: Frame load interrupted and be unable to save the file that is not the case for all mimetype, mimetypes that Safari can display can be opened this way

A little side note here is that window.open only works on trusted events meaning:

  • It will only be able to open the url when user interacts with the website like a onclick event (more about isTrusted event here - almost pointless becuse browser support)

I have also found out that the trusted event persist for 1000 ms, so you could do:

window.onclick = function(){
    setTimeout(function(){
        var blob = new Blob(["Hi"], {type: 'application/octet-stream'});
        var url = URL.createObjectURL(url);
        window.open(url);
    }, 950); // Any longer then 1sec will make the window.open blocked again
}

So the conclusion here about safari is

  1. download attribute in safari is not supported
  2. It will try other means to save the blob by opening a new url
  3. If the mimetype can be rendered by safari it will be able to display it in a new tab
  4. If the mimetype is application/octet-stream:

    4.1 Create a base64 link with FileReader api

    4.2 try to open a new tab using window.open + base64 url

    4.3 if it was more then 1 sec before the user interaction happened it will use the current page instead
    but that is likely going to fail because (see first example using location.href) Failed to load resource: Frame load interrupted This may still work if the mimetype is not application/octet-stream and the saveAs was not called synchronous
  5. Safari don't have anything like msSaveAs()
  6. safest way to force the file to be saved is to have a data:attachment/file" + base64 ready and open that link using window.open() when the user interacts with the website (or at least to it under 1 second)
  7. when saving it as a attachment filename will be "unknown"

noway commented Jan 24, 2013

Your Blob.js uses native blob constructor in Google Chrome, no?
This is defined by this line:

if (typeof Blob !== "function")

ggozad commented Jan 27, 2013

I can verify that Filesaver does not work with 6.0.2. Safari does have a native Blob constructor.
When Blob.js is not included, a new window opens with a blob: url which safari cannot open.
If Blob.js is included, a data: url opens. However the data seems to be the base64 representation of toString of the datea used to construct the blob. In my case where I construct from an array of bytes, I get [object Uint8Array].

Both Chrome, as well as Firefox (opening in a new window as blob) work as advertised.

Does anyone know of a workaround for this?

@Buttyx Buttyx referenced this issue in entwinemedia/annotations Mar 7, 2013

Closed

Category export does not work on Safari 6 #257

marktheunissen commented Jun 17, 2013

This doesn't work on Safari. I suggest updating your REAME.md file so that people are aware of the regression.

Owner

eligrey commented Jun 17, 2013

As I do not have a Mac, I really have no idea what exactly is causing the issue. It's up to you Mac users to fix this or donate a Mac/MacBook to me.

@eligrey eligrey closed this in bc74b4a Jun 17, 2013

@eligrey eligrey reopened this Jun 17, 2013

Owner

eligrey commented Jun 17, 2013

Apparently just mentioning an issue in a commit closes the issue. I didn't mean to do that.

Thanks for updating that. Mountain Lion does run in VirtualBox, if you're interested.

http://www.macbreaker.com/2013/01/iatkos-ml2-mountain-lion-virtualbox.html

Owner

eligrey commented Jun 17, 2013

I used to run OSX in VirtualBox and updates to VB or OSX broke compatibility every so often, so I'd rather not. The lack of hw acceleration is also pretty important.

If you are not a developer you can pay someone who is and owns a Mac to fix this bug if donating a MacBook to me is too much for you. Frankly, seeing as FileSaver.js is a tool for developers most of you are probably developers and you should have no trouble debugging the issue at hand.

Contributor

Keyamoon commented Jun 21, 2013

I tried to reproduce and fix this issue but everything works fine for me in Safari 6 on OS X.

Owner

eligrey commented Jun 21, 2013

@gawry @noway421 @ggozad @bendavis78 @Buttyx @marktheunissen Are you using Blob.js? Is URL, DOMURL, or webkitURL defined in Safari 6? If not, then I can guess that there is no issue and that everyone here is just neglecting to include Blob.js. The Blob API is not solely the Blob constructor, but also the URL.createObjectURL utility. If a browser does not support both of these things, then it needs Blob.js.

@eligrey I'm using Safari 6, and doing testing on the demo page: http://eligrey.com/demos/FileSaver.js/

When clicking the 'Save' button, a new tab opens with the text in it and the url "data:text/plain..." in the address bar.

screen shot 2013-06-21 at 9 00 44 am

screen shot 2013-06-21 at 9 01 07 am

screen shot 2013-06-21 at 9 01 18 am

Owner

eligrey commented Jun 21, 2013

@marktheunissen Thanks. Is URL, DOMURL, or webkitURL defined? If none of those are defined then it seems to be working properly.

Owner

eligrey commented Jun 21, 2013

Tell me if this fixes it for you: eligrey/Blob.js@6f36e8a

I don't have an implementation of FileSaver anywhere to test this change, sorry. I'll let one of the others chime in, as we have moved to a different solution. Thanks for the help.

Owner

eligrey commented Jun 21, 2013

An implementation of FileSaver for testing the change.

Contributor

jordanaustin commented Jun 25, 2013

I use FileSaver.js on a web application and I have support on mobile Safari and Safari on OS X desktop. As long as you include Blob.js as described in the README it works. Please note that Safari has support for Blob constructor but you cannot navigate to a Blob URI, therefore it has to fallback on a Data URI and the data will open in a new window.

There is an issue in Blob.js when attempting to save large images, but that is unrelated to the bug being reported here.

I think this reported bug should be closed unless someone has a specific demo showing the issue described.

@missing What version of Safari? This bug only exists in Safari 6 as far as we know.

I just tried the implementation as provided by @eligrey above in the 'demo' folder on master, and the bug remains.

@missing Yes, it does open the data: URI in a new tab (as you can see in my screenshot above), but isn't the point of this library to make the browser save the file locally?

The other problem is that you can't provide a default filename in this 'fallback' mode, so the user has to re-type it.

Contributor

jordanaustin commented Jun 25, 2013

@marktheunissen I have it working on Safari 6.0.5. So on this demo page it doesn't work? http://eligrey.com/demos/FileSaver.js/

Well, it doesn't behave as expected. It does provide a fallback where you get a data: url, and that does show the correct data in the tab. The problem is that it doesn't trigger the browser to automatically download the data, and when a user chooses "Save As" from the File menu, they have to re-type the name of the file that they typed on the first page.

I'm not sure if this can be fixed by any library, it's probably a deficiency in the Safari browser. All I'm saying is that the user experience provided to Safari users is so different to other browsers, that this should be emphasized in the README so that implementers are aware of it.

Owner

eligrey commented Jun 25, 2013

@marktheunissen Btw, you may be getting a cached version of the page as I have the site configured with pretty aggressive caching, so try clearing your cache before trying again.

and when a user chooses "Save As" from the File menu, they have to re-type the name of the file that they typed on the first page

Safari does not support saving filenames, only Chrome and Firefox (and possibly the new Opera) do at this time.

Contributor

jordanaustin commented Jun 25, 2013

@marktheunissen I understand the frustrations, I've been fighting with Safari and downloading data for a long time as well. The sad fact is that Safari hasn't implemented any of the other fallbacks that can be used here. This library first tries to use the W3C version of FileSaver and then goes to the anchor tag download attribute and finally to data URI. Mobile Safari on iOS handles data URIs in a special way however, if you mimetype it with text/csv for example when it pops you into the new window you'll get the iOS "Open In" bar which lets you open in other applications on your device that have registered as opening csv.

In my opinion Safari hasn't implemented these other filesystem apis because they don't expose the filesystem to users on iOS. Maybe we can update the README to better reflect that.

As of right now filenames work on the follow: Chrome, Firefox 20+ & Opera NEXT (new version of the Blink rendering engine).

Sure thing. I'm not desperate for this bug to be solved in Filesaver, because we aren't using the library. I'm just helping out with testing.

I guess the point is that most people would read the compatibility charts on the README file and expect that the user experience is the same across all browsers - that's the point of a shim like this.

To have a very different user experience for one browser could be a deal breaker for a developer, and it sucks to have to go and test the library before discovering that on Safari it isn't consistent.

Owner

eligrey commented Jun 25, 2013

@missing @marktheunissen I updated the readme to make it clear which browsers support saving filenames and which don't. As it stands, IE10, Firefox, Chrome, and Opera Next support it.

Contributor

jordanaustin commented Jun 25, 2013

@eligrey thanks, was just about to say IE10 too.

badray commented Sep 4, 2013

I got issue with using FileSaver on Safari 6.0.5 on OSX. Including or not the Blob.js does not change nothing. Every time it just redirects me to:
blob:http://myhost/{blob_id}
like:
r6ec

Code sample in coffeescript:

file_parts = []
file_parts.append([1,2,3,4])
file_parts.append([5,6,7,8])
blob = new Blob(file_parts, {type: "application/octet-stream"})
downloaded_file_name = 'file_name'
saveAs(blob, downloaded_file_name)

Looking further for any patches. I also can help with testing it on OSX ;).

Contributor

jordanaustin commented Sep 4, 2013

@badray what about if you try the demo found here: http://eligrey.com/demos/FileSaver.js/

badray commented Sep 5, 2013

@missing i forgot to tell that i tried it :)

Every save button on demo opens a new window instead with generated content opened. Url is always like: "data:{data_mime};charset={charset};base64,{encoded data in base64}"

For example:
rtv3

Contributor

jordanaustin commented Sep 5, 2013

@badray if you look through this thread of comments you'll see that basically the only thing Safari can handle is putting the content into a new window as a dataURL. From that point you can right click and save the data. This is a huge shortcoming on Safari's side. See the comments for more details on it.

On Safari for iOS however, this is definitely the way you want it to work because iOS uses "Open In" rather than exposing the file system. So what happens if you mimetype a document as a CSV for example when you call saveAs (using blob.js) you'll be popped into a new window and you'll get a table of your data, however at the top you'll also get an "Open In" bar which allows any application that has registered to handle CSV to be displayed. You can then open the CSV in whichever app you choose that can handle CSV.

badray commented Sep 6, 2013

@missing ok i understand everything, but this doesn't change the fact that saving blob with some byte stream with mime type application/octet-stream doesn't work on Safari in any way. I think Safari should be marked as 'partialy supported'. I wondering if it is possible to write some flash fallback to achieve this thing.

You can check that with a VM on Mac Safari 6.0.5, it also says that blob urls are not able to display on the page. I hope someone will provide a patch on this. :)

@fcurella fcurella referenced this issue in densitydesign/raw Oct 1, 2013

Closed

[Safari] Download not working #27

I'm hearing about the same problem @badray is having. I just get a blob:http..... error with no way to save the data. A workaround, even a lame one, would be nice.

Hey all. I noticed the same thing, that when testing out the Safari image saving, it tries to open up a blob://file URL and this doesn't work. This with Safari Version 6.0.5 on Mac Os X 10.8.

Now, I tested the Demo Page (http://eligrey.com/demos/FileSaver.js/) on same Safari, and here the image saving correctly falls back to the base64 URI encoding, and you see the image open up on a new tab.

I compared the FileSaver.js, canvas-toBlob.js and Blob.js files on the Demo page to the most recent versions found in github, and figured out that the error is caused by changes in most recent version of Blob.js, updating the two other files didn't affect the image saving.

I copied these two lines:

if (typeof Blob !== "function" || typeof URL === "undefined")
if (typeof Blob === "function" && typeof webkitURL !== "undefined") var URL = webkitURL;

From the previous version that can be found on the demopage, and replaced these two lines:

if (!(typeof Blob === "function" || typeof Blob === "object") || typeof URL === "undefined")
if ((typeof Blob === "function" || typeof Blob === "object") && typeof webkitURL !== "undefined") self.URL = webkitURL;

In the newest version of Blob.js with the lines from above.

And now the image saving works correctly in Safari 6 :)

Also tested this solution working on Safari 5.10.1 running on Mac Os X 10.6.8. So with this solution it seems to work in Safari, both 5 & 6.

Now, I also tested the newest version of Blob.js on Safari 5.10.1, and here the newest version works correctly, falls back to base64 URI encoding. But with Safari 6 it comes up with the blob:// error .. the above solution fixes this for both.

Maybe Safari 5 and Safari 6 are doing something differently when it comes to Blob.js detecting the support, I didn't investigate more on that, all I know that by doing the above it works in all browsers I've tested: Firefox 24, Chrome 30.0.1599.101, Safari 6.0.5 and Safari 5.10.1.

Didn't create a patch for this, but maybe @eligrey you might want to downgrade the support detection to the old one ?

Owner

eligrey commented Oct 21, 2013

I'll leave any code changing decisions to people with Safari 6 (i.e. not me). If any of you feel that you have sufficiently solved this issue, please submit a pullreq and I'll look it over. I will push the latest copies of FileSaver.js, canvas-toBlob.js, and Blob.js to the demo on eligrey.com once I've accepted a pullreq.

Seems like they've fixed something related to Blob handling in Safari 6.1, that came to Software Update couple of weeks ago. So, the code that is now at the repository works with Safari 6.1, but not with 6.0.5. Maybe 6.0.5 was actually broken.

Works also with Safari 5.10.1, it falls back correctly to the dataURI encoding.
Btw. I'm using your code with http://GeoKone.NET, thanks for making canvas-toBlob.js, Blob.js and FileSaver.js @eligrey !! :)

nepaul commented Nov 29, 2016

still not work on macOS Sierra Safari Version 10.0.1 (12602.2.14.0.7)!

Is there even a solution to this issue? Simply changing the mime type is not working for me.

not working in safari version Version 10.0.1 (11602.2.14.0.7)

tsauerwein pushed a commit to tsauerwein/ngeo that referenced this issue Jan 11, 2017

tsauerwein
Generate profile csv on client-side
When starting a CSV export for a profile, a request was made to export the
profile data as CSV. And then a download is started on the client-side.
The problem is that Safari requires that the download is started within 1s
after a user interaction ('trusted event', e.g. clicking the export button).
But by doing the request, this requirement is not fulfilled. To avoid the
request, this PR generates the CSV on the client-side by using the already
available data.
See also: eligrey/FileSaver.js#12

@tsauerwein tsauerwein referenced this issue in camptocamp/ngeo Jan 11, 2017

Merged

Work-around for download on Safari #2177

tsauerwein pushed a commit to tsauerwein/ngeo that referenced this issue Jan 11, 2017

tsauerwein
Generate profile csv on client-side
When starting a CSV export for a profile, a request was made to export the
profile data as CSV. And then a download is started on the client-side.
The problem is that Safari requires that the download is started within 1s
after a user interaction ('trusted event', e.g. clicking the export button).
But by doing the request, this requirement is not fulfilled. To avoid the
request, this PR generates the CSV on the client-side by using the already
available data.
See also: eligrey/FileSaver.js#12

Not working right now on Safari 10. It would be nice to get this information on the presentation page...

I also have this problem. I download file from Angular service:

return $http
        .get(baseUrl + '/downloadReport', {
            responseType: 'arraybuffer',
            params: {
                //some params
            },
        })
        .then(DownloadFileService.downloadExcelFile);

And then inside DownloadFileService:

function downloadExcelFile (response) {
    _downloadFile(response.data, _getFileName(response), DOWNLOAD_FILE.OLDER_EXCEL);
}

function _getFileName (response) {
    return response.headers('Filename');
}

function _downloadFile (fileData, fileName, fileType) {
    FileSaver.saveAs(new $window.Blob([fileData], {type: fileType}), fileName);
}

But in console I got blob:http error. File type is application/vnd.ms-excel.

Same problem here on Safari 10.0. I can't download an application/vnd.ms-excel file type.
But working fine on Chrome & Firefox.

here is a part of my code (angular 2) :

data.service.ts :

exportObject(): Observable<any> {
  const args: RequestOptionsArgs = {
    headers: new Headers({ 'Content-Type': 'application/zip' });,
    responseType: ResponseContentType.Blob
  };
  
  return this.http.get(${this.apiUrl}/exportObject, args).map(
  data => {
    return data.blob();
  });
}

my-component.ts :

this.dataService.exportObject().subscribe(
  blob => {
    saveAs(blob,${this.componentObj.name}-config.zip);
  }
);

FileSaver.js works for me in my application and on the demo page in the latest Safari Technology Preview Release 23 (Safari 10.2, WebKit 12604.1.5) on Sierra. Saves to the Downloads folder with the correct filename and everything!

(Might have been fixed in a previous Preview release. I can't recall the last Preview I tried.)

Also works in Safari 10.1 in the latest macOS Sierra 10.12.4 Beta, so I would guess that real users might get this in the next few months.

meletis commented Mar 29, 2017

Yes, confirmed. I also works for me in Safari 10.1 released yesterday.

Confirmed it's working on Safari 10.1, but not in previous versions.

Collaborator

jimmywarting commented May 22, 2017

Should we close this issue now? ;P

toby5box commented Jun 10, 2017

FWIW I can report this problem still exists on Safari 9.1.1 (El Capitan).

I am also experiencing the same issue on Safari 9.1.2 (El Capitan).

Yes. Let's update supported browser in README and close this issue.

@harshavardhana harshavardhana referenced this issue in minio/minio Jul 15, 2017

Closed

(wip) browser: remove token from GET URLs #4673

4 of 8 tasks complete

Ruffio commented Jul 29, 2017

@eligrey if this issue is resolved/closed, should the Frontpage be updated?

Currently it states:
Safari 6.1+

Blobs may be opened instead of saved sometimes—you may have to direct your Safari users to manually press ⌘+S to save the file after it is opened. Using the application/octet-stream MIME type to force downloads can cause issues in Safari.

tayfunyasar commented Oct 11, 2017

It still doesn't work in my tablet.
IOS: 11.0.2 (15A421)

var wbout = XLSX.write(wb, {
  bookType: 'xlsx',
  bookSST: false,
  type: 'binary',
});
fileSaver.saveAs(new Blob([s2ab(wbout)], {
  type: 'application/octet-stream',
}), name);

I can agree with @tayfunyasar, it's not working on iOS for me. I have submitted a bug report to Apple regarding the lack of download attribute for all the good it's likely to do.

@eligrey eligrey changed the title from Problems saving in some versions of Safari to Problems saving in iOS Safari Dec 7, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment