IOS 10.3.1 cordova based App crashes when trying to write to IndexedDB - ios

I'm developing a cordova-based multi-platform web-app using sapui5 framework v1.44 and indexedDB for storing data.The app was working fine untill last ios update, 10.3.1, now it crashes when trying to write to indexedDB. I'm using put method for updating data and i did a clean install of the app. The code frame where i try to write to indexedDB is this:
writeToIDB: function (objStoreName, result, success, error) {
//Asynchronous function
var defer = Q.defer();
var res = [];
if (!!result && Array.isArray(result)) {
res = result;
} else if (!!result && result.hasOwnProperty("results") && Array.isArray(result.results)) {
res = result.results;
} else if (!!result && typeof result === 'object') {
res.push(result);
}
if (res.length >= 0) {
if (window.myDB) {
if (!window.myDB.objectStoreNames.contains(objStoreName)) {
console.log("ObjectStore for " + objStoreName + " doesn't exist");
if (error) {
error("ko")
} else {
defer.reject("ko");
}
} else {
var oTransaction = window.myDB.transaction([objStoreName], "readwrite");
var oDataStore = oTransaction.objectStore(objStoreName);
oTransaction.oncomplete = function (event) {
console.log("Transaction completed: database modification for " + objStoreName + " finished.");
if (success) {
success();
} else {
defer.resolve("ok");
}
};
oTransaction.onerror = function (event) {
console.log("Transaction for " + objStoreName + " not opened due to error. Check for duplicate items or missing properties!");
console.log(event.target.error);
if (error) {
error("ko")
} else {
defer.reject("ko");
}
};
var oRecord = {};
for (var i = 0; i < res.length; i++) {
oRecord = res[i];
oDataStore.put(oRecord);
}
}
} else {
this.createIDB().then(
function (resCreate) {
console.log("DB Created successfully");
if (!window.myDB.objectStoreNames.contains(objStoreName)) {
console.log("ObjectStore for " + objStoreName + " doesn't exist");
if (error) {
error("ko")
} else {
defer.reject("ko");
}
} else {
var oTransaction = window.myDB.transaction([objStoreName], "readwrite");
var oDataStore = oTransaction.objectStore(objStoreName);
oTransaction.oncomplete = function (event) {
console.log("Transaction completed: database modification for " + objStoreName + " finished.");
if (success) {
success();
} else {
defer.resolve("ok");
}
};
oTransaction.onerror = function (event) {
console.log("Transaction for " + objStoreName + " not opened due to error. Check for duplicate items or missing properties!");
console.log(event.target.error);
if (error) {
error("ko")
} else {
defer.reject("ko");
}
};
var oRecord = {};
for (var i = 0; i < res.length; i++) {
oRecord = res[i];
oDataStore.put(oRecord);
}
}
}.bind(this),
function (err) {
console.log("DB Creation failed");
if (error) {
error("ko")
} else {
defer.reject("ko");
}
}.bind(this)
);
}
} else {
if (error) {
error("ko")
} else {
defer.reject("ko");
}
}
if (typeof success === 'undefined' && typeof error === 'undefined') {
return defer.promise;
}
},
P.S.I have omitted parts of the code.
This was working fine with the previous version of ios, i think i had installed the 10.2.1, now it simply crashes after calling the put method. I tried upgrading now ios to the beta of 10.3.2 but the result is the same. Anyone else noticed this or have any idea of how to resolve this problem?
Thanks
K
UPDATE
I've found the issue: the complex dataTypes. Since IndexedDB supports saving and retrieving complex dataTypes, i had some properties which were arrays or objects that i used to save in some of my ObjectStores. This is definitely a big problem for me because the only workaround i can think for this is to stingify the complex fields but since i work with a lot of data this would create a big performance issue. I hope the ios developer team will find a solution for this soon enough

Are you sure every key in the res[] array is a valid key? There is a closed bug here:
https://bugs.webkit.org/show_bug.cgi?id=170000
It looks if you pass in an invalid key it will cause webkit to crash.
This fix for this will likely be contained in the next public release of iOS.
To determine what a valid key is see this section of the W3.org spec:
3.1.3 Keys
In order to efficiently retrieve records stored in an indexed database, each record is organized according to its key. A value is said to be a valid key if it is one of the following ECMAScript [ECMA-262] types: Number primitive value, String primitive value, Date object, or Array object. An Array is only a valid key if every item in the array is defined and is a valid key (i.e. sparse arrays can not be valid keys) and if the Array doesn't directly or indirectly contain itself. Any non-numeric properties on an Array are ignored, and thus do not affect whether the Array is a valid key. If the value is of type Number, it is only a valid key if it is not NaN. If the value is of type Date it is only a valid key if its [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN. Conforming user agents must support all valid keys as keys.
This was taken from here:
https://www.w3.org/TR/IndexedDB/#key-construct

Not sure if it's the same issue, but I had a crash on iOS 10.3 that I didnt get in any other browser. Using Dexie wrapper for indexedDB, I did a get all records from table search:
db.table.toArray(function (results) {
// process...
})
and got flames from Xcode to what looked like a threading issue in WebKit so I just added setTimeout( ... ,1) and that hacked around the problem for me.

Related

SELECT statement no longer working after installing cordova-plugin-ionic-webview

I was trying to fix some performance issues in my ionic hybrid app when using AWS cognito which requires installing cordova-plugin-ionic-webview. However, after installing this plugin, my SELECT statement is no longer working - it is now returning no records found. Here is the statement:
dbAccess.SelectGoodsReceiptDetail = function SelectGoodsReceiptDetail(goodsreceipt) {
var resultData = {};
// Select Multiple Items
return $q(function(resolve, reject) {db.executeSql("SELECT * FROM goodsreceiptdetailview WHERE goodsReceiptKey LIKE ?", [ goodsreceipt.header.goodsReceiptKey] , function(rs) {
resultData.data = [{}];
if (rs.rows.length > 0) {
if (rs.rows.item) {
for (i=0;i<rs.rows.length; i++) {
resultData.data[i] = rs.rows.item(i);
}
resultData.exist = true;
}
} else {
// no item found
resultData.exist = false;
}
resolve(resultData);
}, function(error) {
resultData.data = [{}];
resultData.exist = false;
resultData.failed = true;
resolve(resultData);
})
});
}
The variable goodsreceipt.header.goodsReceiptKey in an integer. I have read in the release notes for the cordova sqlite plugin that whole numbers are treated as REAL values when using WKWebView while it is being treated as INT on UIWebView here. Could this be causing the problem? How can I fix this with WKWebView?
I was able to fix this by converting the INT to string.

Phonegap/Cordova pre populated SQLite data retrieve too slow

The Phonegap/Cordova project using https://github.com/brodysoft/Cordova-SQLitePlugin for using SQLite. There is minor changes made in MainViewController.m to use pre-populated databse (however it might not effect the problem).
The database detecting very well here is the databaase detecting code
function onDeviceReady() {
db = window.sqlitePlugin.openDatabase({name: "database.db"});
db.transaction(queryDB, errorCB);
function queryDB(tx) {
console.log("started");
tx.executeSql("select * from user_info", [], function(tx, res) {
console.log("res.rows.length: " + res.rows.length);
});
}
function errorCB(err) {
console.log("Error processing SQL : "+err.message);
}
}
Result
res.rows.length: 1
Here is the retrieving data code which takes about 10 sec to show result :(
function callMe (argument) {
db.transaction(buttonqueryDB, buttonerrorCB);
function buttonqueryDB(transaction) {
console.log("going to query");
transaction.executeSql('SELECT * FROM home_word', [], function(transaction, result) {
console.log("total itemes " + result.rows.length);
if (result != null && result.rows != null) {
for (var i = 0; i < 10; i++) {
var row = result.rows.item(i);
console.log("this result : " +row.word);
}
}
});
}
function buttonerrorCB(err) {
console.log("Error processing SQL : "+err.message);
}
}
The going to query shows quickly and query result display takes about 10sec

Why am I getting this error in a basic Rails+Ember app?

I am trying to do a simple CRUD app using Ember + Rails and I'm getting the following error when trying to go to the /workouts route.
Error while loading route: TypeError {} ember.js?body=1:415
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, undefinedDescriptor);
o_defineProperty(this, '_super', undefinedDescriptor);
var m = meta(this), proto = m.proto;
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
for (var keyName in properties) {
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
Ember.assert("`actions` must be provided at extend time, not at create time, when Ember.ActionHandler is used (i.e. views, controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this)));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
this.init.apply(this, arguments);
m.proto = proto;
finishChains(this);
sendEvent(this, "init");
} has no method 'find'
My code is located here: https://github.com/ecl1pse/ember-workouts
What am I doing wrong?
Edit: Upon further investigation I believe the culprit is
EmberWorkouts.WorkoutsRoute = Ember.Route.extend(
model: -> EmberWorkouts.Workout.find()
This doesn't actually return anything. How do I debug from there?
If I replace that with this
EmberWorkouts.WorkoutsRoute = Ember.Route.extend
model: -> [{title: 'hi'}, {title: 'damn'}]
The view actually renders content.
How do I get the model to collect from Rails properly?
Ember Data's interface has changed a little with the current release:
You can clear out the store.js file entirely. Ember Data will automatically set up a data store for you using the REST Adapter (unless you tell it otherwise).
Use model: -> #store.find('workout') instead.
I tested this with your app and it works.
If you haven't read through the Ember Data Guide in the last week or two (it's changed a lot), I would spend a few minutes on it.
The fix for this error (as of ember-data 1.0.0.beta.6) for me was to make sure that the JSON returned from the server included an "id" field for each model, BUT not to explicitly declare the id when setting up the Ember DS.Model.
jbuilder template:
json.scans do
json.array! #scans do |scan|
json.id scan.id # This prop has to be there
json.name scan.name
end
end
Ember model:
EmberApp.Scan = DS.Model.extend(
// Don't include the id prop here
name: DS.attr("string")
)

Can't open sqlite database with phonegap but it works fine on objectiveC

I have a SQLITE database on my iOS project, which I can access from my native IOS code. I can access it and read data from it.
You can see the way i'm doing it and my project structure in the following pic:
And i try to do the same using Phonegap:
var db;
var shortName = 'myTestDb.db';
var version = '1.0';
var displayName = 'myTestDb';
var maxSize = 65535;
// list the values in the database to the screen using jquery to
//update the #lbUsers element
function ListDBValues() {
if (!window.openDatabase) {
alert('Databases are not supported in this browser.');
return;
}
$('#myDbElements').html('');
db.transaction(function(transaction) {
transaction.executeSql("SELECT FIRST_NAME FROM dbo_RE_USER;", [],
function(transaction, result) {
console.log("result");
if (result != null && result.rows != null) {
console.log("result is not null");
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
//console.log(row);
debugObject(row);
$('#myDbElements').append('<br>' + row["FIRST_NAME"]);// + " " + row.LAST_NAME );
}
}
PrecApp.I_SCROLL.refresh();
},errorHandler);
},errorHandler,nullHandler);
return;
}
function debugObject(obj) {
console.log("ROW:");
for (n in obj)
// alert(n + ":" + obj[n]);
console.log(n + ":" + obj[n]);
}
But it can't find my dbo_re_users table. Why?
The database opened in JavaScript is an entirely different database - it has the same name, but is not in the app bundle, which is read only.
If you need to access a specific database file, you will need to use a plugin.

Blackberry File (Webworks)

I'm trying (Very simply) to get a file list of the camera directory using webworks.
The code I'm trying is as follows:
function displayPhotos(id) {
try {
var Dir, path, items;
if ((window.blackberry === undefined) || (blackberry.io === undefined) || (blackberry.io.file === undefined)) {
appendContent("photoDetails", "<p><i><b>blackberry.io.file</b> object not found (likely cause is WebWorks APIs are not supported by this user agent).</i></p>");
debug.log("displayPhotos", "blackberry.io.file object is undefined.", debug.error);
return false;
}
Dir = blackberry.io.dir;
path = "";
path = "file:///Device/home/user/camera"";
items = Dir.listFiles(path);
console.log(items);
//setContent(id, formatAsHTML(path, items));
}
catch(e) {
console.log("displayPhotos", e, debug.exception);
}
}
All I get back is error 1004 - I assume this is permissions based, but I fail to believe I can't get a READ on the camera fails - any one know anything?
Cheers!
Well I figured it out, hope this helps anyine getting the dreaded blackberry webworks error 1004.
You need to change device in the path to store. That's it really. This example works:
function displayPhotos(myFolder) {
try {
var Dir, path, items;
Dir = blackberry.io.dir;
path = "";
if (myFolder != undefined){
path = myFolder;
} else {
path = "file:///store/home/user/pictures";
//file:///store/home/user/camera
}
items = Dir.listFiles(path);
return items;
}
catch(e) {
console.log("displayPhotos", e, debug.exception);
}
}
function displayFiles(myFolder) {
try {
console.log("displayFiles", "in " + myFolder);
return displayPhotos(myFolder);
}
catch(e) {
console.log("displayFiles", e, debug.exception);
}
}
You can call it like so:
displayFiles();
Or specify a folder like so:
displayFiles("file:///store/home/user/camera");
Returns an array of filenames.
Hope this helps someone!

Resources