IndexedDB in Safari 10 supports blobs now. This works fine on desktop, however mobile Safari on iOS 10 throws an error:
UnknownError
and sometimes in combination:
TransactionInactiveError (DOM IDBDatabase Exception): Failed to store record in an IDBObjectStore:
The transaction is inactive or finished.
The code (shortened):
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB,
READ_WRITE = IDBTransaction && IDBTransaction.READ_WRITE ? IDBTransaction.READ_WRITE : 'readwrite',
storeName = 'files',
db;
init: function() {
var request = indexedDB.open('mydb');
request.onerror = ...;
request.onupgradeneeded = function() {
db = request.result;
db.createObjectStore(storeName);
};
request.onsuccess = function() {
db = request.result;
};
},
save: function(id, data) {
var put = function(data) {
var objectStore = db.transaction([storeName], READ_WRITE).objectStore(storeName),
request = objectStore.put(data, id);
request.onerror = ...;
request.onsuccess = ...;
};
// not all IndexedDB implementations support storing blobs, only detection is try-catch
try {
put(data);
} catch(err) {
if (data instanceof Blob) {
Helpers.blobToDataURL(data, put);
}
}
}
On Mobile Safari 10 .put()
doesn't throw like before, only later in the async error-callback.
Base64 strings work fine.
Bug in Mobile Safari or do I have to change code?
Test Case: http://fiddle.jshell.net/j7wh60vo/7/
Ran across the same problem. Chrome 54 and Safari 10 work fine on desktop, but on Mobile Safari I kept getting the Unknown
error when trying to store a Blob into IndexedDB. I can confirm that this really is just an issue with Blobs on Mobile Safari, and not some misuse of the API.
Fortunately, ArrayBuffers work fine. So I instead downloaded the images like:
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
Then saved them into IndexedDB as ArrayBuffers, and converted them to Blobs after pulling them out to get a url:
putRequest = objectStore.put(arrayBuffer, id);
putRequest.onsuccess = function(event) {
objectStore.get(id).onsuccess = function(event) {
var blob = new Blob([event.target.result], { type: 'image/jpeg'});
var URL = window.URL || window.webkitURL;
blobUrl = URL.createObjectURL(blob);
};
};
I'd rather not have to convert ArrayBuffers to Blobs like this as I assume there is a performance penalty. But it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With