Open Blob URL in new window on iPhone and iPad Safari Browsers

3.5k Views Asked by At

I am trying to generate a PDF file based on the response returned from the server and open the file in new tab. It works very well in Desktop across all browsers but has problem in apple devices (iphone + ipad) in safari browser.

Here is the code snippet:

if (responseType = base64 encoded string like JVBERi0xLjUKJeLjz9MKMSAwI....) {
   const binaryString = window.atob(fileResponseData);
   const bytes = new Uint8Array(binaryString.length);
   const binaryToBlob = bytes.map((byte, i) => binaryString.charCodeAt(i));
   const blob = new Blob([binaryToBlob], { type: 'application/pdf' });
   this.downloadFile(blob, fileName);
} else {
   // blob response like %PDF-1.7 %âãÏÓ5 0 obj....
   const blob = new Blob([fileResponseData], { type: 'application/pdf' });
   this.downloadFile(blob, fileName);
}

This is how I am downloading the file

if (window.navigator && window.navigator.msSaveOrOpenBlob) {
   window.navigator.msSaveOrOpenBlob(blob, fileName);
   return;
}

const url = (window.URL || window.webkitURL).createObjectURL(blob);
window.open(url, '_blank');

I know there are related articles regarding this topic, but they didn't solved my problem. Infact I came up with above code referring to those articles itself but still I am facing problem in apple devices. As soon as I click button to generate file and display in new tab, nothing happens on apple device, but other devices works just fine.

3

There are 3 best solutions below

0
On

I had same problem in my react application where I wanted to open pdf blob url in new tab, iPad safari didn't allow me to do so but other devices and browses allowed. Please refer below code when you wanted to open the pdf blob url in new tab on ipad safari:

     // checks if the user agent string contains any of the keywords 
        "iPad", "iPhone", "iPod", "Macintosh", or "Mac". This covers most 
      Apple devices, including those running Safari.
     if (/iPad|iPhone|iPod|Macintosh|Mac/.test(navigator.userAgent)) {
        //assumes you have a doc object containing the PDF data. It 
          asynchronously saves the data to a byte array./
        const bBody = await doc.save();

        //This creates a Blob object representing the PDF data with the 
         correct mime type.
        const blob = new Blob([bBody], { type: "application/pdf" });
        const reader = new FileReader();

      //callback function that gets called when the data is read
        reader.onload = () => {
          const iframe:any = document.getElementById("myIframe");
          iframe.src = reader.result; // Non-null assertion    
        
       };

        reader.readAsDataURL(blob);
    } 
0
On

I experienced an issue if the download time of the file took longer than about 1 second (997ms) or if the click event on the link was triggered later than 1 second after the user clicked. You can try it with this code:

Immediately after the click open a new window:

let myWindow = null
const winHtml = `<!DOCTYPE html><html><head><title>Downloading file, please wait</title><head><body><h1>Downloading file, please wait</h1></body></html>`
const winUrl = URL.createObjectURL(
    new Blob([winHtml], { type: 'text/html' })
)
myWindow = window.open(winUrl, '_blank')

Now start the download. Once the download has finished change the location to the created object url from the blob:

const url = (window.URL || window.webkitURL).createObjectURL(blob)
if (myWindow === null)
    window.open(url, '_blank')
else
    myWindow.location.href = url
0
On

I have the same problem on my iPhone 6s+ using iOS 14.3. Looks like it's a feature of Safari on iPhone/iPad that blocks popups if the window.open() stays in some various events (for example onload/onloadend event, or setTimeout). You can try moving window.open() into another scope or function to see the results.

As for my issue, I solve it by creating a hidden anchor tag and then click it:

mySmallDiv.innerHTML = '<a href="+'url'+" target="_blank" id="openPdf">&nbsp;</a>';
document.getElementById("openPdf").click();

But Safari may still blocks it, so please change your code accordingly.
And, don't forget to call URL.revokeObjectURL(url) after a timeout.

Besides, I think you need to use FileReader() if the browser is Chrome iOS.