EDIT: I have found a more concise solution that seems to solve this problem. It basically creates an iframe and uses the iframe's navigator to share instead of the page, that way you can hard reload the iframe every time you share to prevent it from hanging.
// create an invisible "sharing iframe" once
var sharingIframe = document.createElement("iframe");
var sharingIframeBlob = new Blob([`<!DOCTYPE html><html>`],{type:"text/html"});
sharingIframe.src = URL.createObjectURL(sharingIframeBlob);
sharingIframe.style.display = "none"; // make it so that it is hidden
document.documentElement.appendChild(sharingIframe); // add it to the DOM
// do not revoke the blob url because you will be reloading it later.
// also note that the following function must only be run after the iframe
// loads (and the iframe.contentWindow.navigator, which is what we are using)
function share(file){
sharingIframe.contentWindow.navigator.share({files:[file]}).then(()=>{
console.log("files shared");
sharingIframe.contentWindow.location.reload(true); // reload sharing iframe to fix iOS bug
}).catch((err)=>{
console.error("user cancelled share");
sharingIframe.contentWindow.location.reload(true); // reload sharing iframe to fix iOS bug
});
}
My old, messier solution from earlier:
I encountered the same annoying bug, even with IOS 15+ safari still acts weird with navigator.share. my solution was to essentially create a temporary iframe when sharing something, using the iframe's contentWindow.navigator instead of the top window, and then closing/removing the iframe to kill the reference every time so it doesn't hang.
function share(file){
// first, create temporary iframe and construct a temporary HTML file
// this serves as a sort of modal to click thru and sits on top
// of the main window until it is dismissed
var iframe = document.createElement("iframe");
var iframeText = `
<!DOCTYPE html>
<html style="position:absolute;width:100%;height:100%;background-color:rgba(0,0,0,0.5);">
<div style="position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);padding:10px;background-color:rgba(255,255,255,0.5);;">
<button id="cancel">cancel</button>
<button id="download">download</button>
</div>
</html>
`;
var iframeBlob = new Blob([iframeText],{type:"text/html"});
iframe.src = URL.createObjectURL(iframeBlob);
iframe.style.all = "unset";
iframe.style.position = "fixed";
iframe.style.width = "100%";
iframe.style.height = "100%";
document.body.appendChild(iframe);
iframe.onload=()=>{
URL.revokeObjectURL(iframe.src); // delete the object URL
// select the elements in the iframe and add event handlers
// to either share the file or dismiss and close the dialogue
// (the iframe will close automatically after being dismissed
// or if the user cancels share by tapping away)
iframe.contentDocument.querySelector("#download").onclick=()=>{
iframe.contentWindow.navigator.share({files:[file]}).then(()=>{
console.log("files shared");
iframe.contentWindow.close();
iframe.remove();
}).catch((err)=>{
console.error("user cancelled share");
iframe.contentWindow.close();
iframe.remove();
});
};
iframe.contentDocument.querySelector("#cancel").onclick=()=>{
iframe.contentWindow.close();
iframe.remove();
};
};
}