CustomWebView
CustomWebView copied to clipboard
Feature Request: Support for downloading `blob` URLs
Could support be added to download blob: URLs? I have done some research on how this could be done. I found this issue which sounds like the current problem with downloading blob URLs. I made the following code to take care of a few concerns I had about the examples' code.
Code
(async function() {
const blobUrl = null; // Some blob URL from App Inventor.
const { revokeObjectURL } = URL; // Backup the original URL.revokeObjectURL method
const restoreRevokeObjectURL = () => URL.revokeObjectURL = revokeObjectURL; // Restore the URL.revokeObjectURL method
let Blob2Base64Finished = false;
// Temporarily make the blob URL being downloaded not revocable.
(function(url) {
url.revokeObjectURL = objectUrl => {
// Incase a different blob URL needs to be revoked
if(objectUrl != blobUrl) {
revokeObjectURL(objectUrl);
}
// Skip the interval check if it already completed
if(Blob2Base64Finished === true) {
revokeObjectURL(objectUrl);
restoreRevokeObjectURL();
} else {
const interval = setInterval(() => {
if(Blob2Base64Finished === true) {
clearInterval(interval);
revokeObjectURL(objectUrl);
restoreRevokeObjectURL();
}
}, 100);
}
}
})(URL)
// Convert a blob to a data URL
function Base64PromiseFileReader(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener("loadend", () => resolve(reader.result));
reader.addEventListener("onerror", e => reject(e));
reader.readAsDataURL(blob);
});
}
function readBlobUrl(blobUrl) {
return new Promise(async (resolve, reject) => {
try {
// Convert the blob URL to a blob
const blob = await (await fetch(blobUrl)).blob();
// Convert the blob to a data URL
resolve(await Base64PromiseFileReader(blob));
} catch(e) {
reject(e.message == "Failed to fetch" ? "Blob Revoked" : e);
}
});
}
const result = await readBlobUrl(blobUrl); // Get the data URL form the blob URL
Blob2Base64Finished = true; // Tell the modified URL.revokeObjectURL that converting the blob to a data URL was completed
// Gives the modified URL.revokeObjectURL a chance to run before replacing it with the original
setTimeout(() => restoreRevokeObjectURL(), 150);
// Return `result` to the app to be downloaded
})();
I don't know how hard it would be to actually implement the java part of this, but it looks like it would be pretty simple.
Thanks for this amazing extension @vknow360!
I'll work on this but there is very thin possibility that it will work.
https://github.com/vknow360/CustomWebView/commit/0c3cdb662d69559f50ddbfdbf2a5842a46ab32f1 adds this feature